The latest release of the FreeBSD driver (twa) for

3ware's 9xxx series controllers.  This corresponds to
the 9.2 release (for FreeBSD 5.2.1) on the 3ware website.

Highlights of this release are:

1. The driver has been re-architected to use a "Common Layer"
    (all tw_cl* files), which is a consolidation of all OS-independent
    parts of the driver.  The FreeBSD OS specific portions of the
    driver go into an "OS Layer" (all tw_osl* files).
    This re-architecture is to achieve better maintainability, consistency
    of behavior across OS's, and better portability to new OS's (drivers
    for new OS's can be written by just adding an OS Layer that's specific
    to the OS, by complying to a "Common Layer Programming Interface" API.

2. The driver takes advantage of multiple processors.

3. The driver has a new firmware image bundled, the new features of which
   include Online Capacity Expansion and multi-lun support, among others.
   More details about 3ware's 9.2 release can be found here:
   http://www.3ware.com/download/Escalade9000Series/9.2/9.2_Release_Notes_Web.pdf

Since the Common Layer is used across OS's, the FreeBSD specific include
path for header files (/sys/dev/twa) is not part of the #include pre-processor
directive in any of the source files.  For being able to integrate twa into
the kernel despite this, Makefile.<arch> has been changed to add the include
path to CFLAGS.

Reviewed by: scottl
This commit is contained in:
Vinod Kashyap 2005-04-12 22:07:11 +00:00
parent 93fa9a8d72
commit f0c1dee27f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=144966
38 changed files with 36496 additions and 31888 deletions

View File

@ -87,4 +87,6 @@ __reml.S: $S/$M/$M/divrem.m4
%RULES
CFLAGS+=-I/sys/dev/twa
.include "$S/conf/kern.post.mk"

View File

@ -52,4 +52,6 @@ MKMODULESENV+= MACHINE=amd64
%RULES
CFLAGS+=-I/sys/dev/twa
.include "$S/conf/kern.post.mk"

View File

@ -58,4 +58,6 @@ ldscript.$M: $S/conf/ldscript.$M
sed s/KERNVIRTADDR/${KERNVIRTADDR}/g > ldscript.$M
%RULES
CFLAGS+=-I/sys/dev/twa
.include "$S/conf/kern.post.mk"

View File

@ -46,4 +46,6 @@ MKMODULESENV+= MACHINE=i386
%RULES
CFLAGS+=-I/sys/dev/twa
.include "$S/conf/kern.post.mk"

View File

@ -52,4 +52,6 @@ ASM_CFLAGS= -x assembler-with-cpp -Wa,-x -DLOCORE ${CFLAGS}
%RULES
CFLAGS+=-I/sys/dev/twa
.include "$S/conf/kern.post.mk"

View File

@ -46,4 +46,6 @@ MKMODULESENV+= MACHINE=pc98
%RULES
CFLAGS+=-I/sys/dev/twa
.include "$S/conf/kern.post.mk"

View File

@ -51,4 +51,6 @@ CFLAGS+= -fno-omit-frame-pointer
%RULES
CFLAGS+=-I/sys/dev/twa
.include "$S/conf/kern.post.mk"

View File

@ -46,4 +46,6 @@ MDOBJS= exception.o interrupt.o
%RULES
CFLAGS+=-I/sys/dev/twa
.include "$S/conf/kern.post.mk"

View File

@ -799,11 +799,13 @@ dev/syscons/star/star_saver.c optional star_saver
dev/syscons/warp/warp_saver.c optional warp_saver
dev/tdfx/tdfx_pci.c optional tdfx pci
dev/trm/trm.c optional trm
dev/twa/twa.c optional twa
dev/twa/twa_cam.c optional twa
dev/twa/twa_freebsd.c optional twa
dev/twa/twa_fwimg.c optional twa
dev/twa/twa_globals.c optional twa
dev/twa/tw_cl_fwimg.c optional twa
dev/twa/tw_cl_init.c optional twa
dev/twa/tw_cl_intr.c optional twa
dev/twa/tw_cl_io.c optional twa
dev/twa/tw_cl_misc.c optional twa
dev/twa/tw_osl_cam.c optional twa
dev/twa/tw_osl_freebsd.c optional twa
dev/twe/twe.c optional twe
dev/twe/twe_freebsd.c optional twe
dev/tx/if_tx.c optional tx

406
sys/dev/twa/tw_cl.h Normal file
View File

@ -0,0 +1,406 @@
/*
* 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
*/
#ifndef TW_CL_H
#define TW_CL_H
/*
* Common Layer internal macros, structures and functions.
*/
#define TW_CLI_SECTOR_SIZE 0x200
#define TW_CLI_REQUEST_TIMEOUT_PERIOD 60 /* seconds */
#define TW_CLI_RESET_TIMEOUT_PERIOD 60 /* seconds */
#define TW_CLI_MAX_RESET_ATTEMPTS 2
#ifdef TW_OSL_FLASH_FIRMWARE
/* Number of chunks the fw image is broken into, while flashing. */
#define TW_CLI_NUM_FW_IMAGE_CHUNKS 500
#endif /* TW_OSL_FLASH_FIRMWARE */
/* Possible values of ctlr->state. */
/* Initialization done, and controller is active. */
#define TW_CLI_CTLR_STATE_ACTIVE (1<<0)
/* Interrupts on controller enabled. */
#define TW_CLI_CTLR_STATE_INTR_ENABLED (1<<1)
/* Data buffer for internal requests in use. */
#define TW_CLI_CTLR_STATE_INTERNAL_REQ_BUSY (1<<2)
/* More AEN's need to be retrieved. */
#define TW_CLI_CTLR_STATE_GET_MORE_AENS (1<<3)
/* Controller is being reset. */
#define TW_CLI_CTLR_STATE_RESET_IN_PROGRESS (1<<4)
/* Possible values of ctlr->ioctl_lock.lock. */
#define TW_CLI_LOCK_FREE 0x0 /* lock is free */
#define TW_CLI_LOCK_HELD 0x1 /* lock is held */
/* Possible values of req->state. */
#define TW_CLI_REQ_STATE_INIT 0x0 /* being initialized */
#define TW_CLI_REQ_STATE_BUSY 0x1 /* submitted to controller */
#define TW_CLI_REQ_STATE_PENDING 0x2 /* in pending queue */
#define TW_CLI_REQ_STATE_COMPLETE 0x3 /* completed by controller */
/* Possible values of req->flags. */
#define TW_CLI_REQ_FLAGS_7K (1<<0) /* 7000 cmd pkt */
#define TW_CLI_REQ_FLAGS_9K (1<<1) /* 9000 cmd pkt */
#define TW_CLI_REQ_FLAGS_INTERNAL (1<<2) /* internal request */
#define TW_CLI_REQ_FLAGS_PASSTHRU (1<<3) /* passthru request */
#define TW_CLI_REQ_FLAGS_EXTERNAL (1<<4) /* external request */
#ifdef TW_OSL_PCI_CONFIG_ACCESSIBLE
/* Register offsets in PCI config space. */
#define TW_CLI_PCI_CONFIG_COMMAND_OFFSET 0x4 /* cmd register offset */
#define TW_CLI_PCI_CONFIG_STATUS_OFFSET 0x6 /* status register offset */
#endif /* TW_OSL_PCI_CONFIG_ACCESSIBLE */
#pragma pack(1)
#ifdef TW_OSL_DEBUG
struct tw_cli_q_stats {
TW_UINT32 cur_len;/* current # of entries in q */
TW_UINT32 max_len; /* max # of entries in q, ever reached */
};
#endif /* TW_OSL_DEBUG */
/* Queues of CL internal request context packets. */
#define TW_CLI_FREE_Q 0 /* free q */
#define TW_CLI_BUSY_Q 1 /* q of reqs submitted to fw */
#define TW_CLI_PENDING_Q 2 /* q of reqs deferred due to 'q full' */
#define TW_CLI_COMPLETE_Q 3 /* q of reqs completed by fw */
#define TW_CLI_Q_COUNT 4 /* total number of queues */
/* CL's internal request context. */
struct tw_cli_req_context {
struct tw_cl_req_handle *req_handle;/* handle to track requests between
OSL & CL */
struct tw_cli_ctlr_context *ctlr; /* ptr to CL's controller context */
struct tw_cl_command_packet *cmd_pkt;/* ptr to ctlr cmd pkt */
TW_UINT64 cmd_pkt_phys; /* cmd pkt physical address */
TW_VOID *data; /* ptr to data being passed to fw */
TW_UINT32 length; /* length of data being passed to fw */
TW_UINT64 data_phys; /* physical address of data */
TW_UINT32 state; /* request state */
TW_UINT32 flags; /* request flags */
TW_UINT32 error_code; /* error encountered before submission
of request to fw, if any */
TW_VOID *orig_req; /* ptr to original request for use
during callback */
TW_VOID (*tw_cli_callback)(struct tw_cli_req_context *req);
/* CL internal callback */
TW_UINT32 request_id; /* request id for tracking with fw */
struct tw_cl_link link; /* to link this request in a list */
};
/* CL's internal controller context. */
struct tw_cli_ctlr_context {
struct tw_cl_ctlr_handle *ctlr_handle; /* handle to track ctlr between
OSL & CL. */
struct tw_cli_req_context *req_ctxt_buf;/* pointer to the array of CL's
internal request context pkts */
#ifdef TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST
TW_UINT32 free_req_ids[TW_CL_MAX_SIMULTANEOUS_REQUESTS];
/* Array of free req_id's */
struct tw_cli_req_context *busy_reqs[TW_CL_MAX_SIMULTANEOUS_REQUESTS + 1];
/* Array of busy reqs -- index is req_id */
TW_UINT32 free_req_head;
TW_UINT32 free_req_tail;
TW_UINT32 num_free_req_ids;
#endif /* TW_OSL_DMA_MEM_ALLOC_PER_REQUEST */
struct tw_cl_command_packet *cmd_pkt_buf;/* ptr to array of cmd pkts */
TW_UINT64 cmd_pkt_phys; /* phys addr of cmd_pkt_buf */
TW_UINT32 state; /* controller state */
TW_UINT32 flags; /* controller settings */
/* Request queues and arrays. */
struct tw_cl_link req_q_head[TW_CLI_Q_COUNT];
#ifdef TW_OSL_FLASH_FIRMWARE
TW_VOID *flash_dma_mem; /* mem for flashing fw image */
TW_UINT64 flash_dma_mem_phys;/* flash_dma_mem phys addr */
#endif /* TW_OSL_FLASH_FIRMWARE */
TW_UINT8 *internal_req_data;/* internal req data buf */
TW_UINT64 internal_req_data_phys;/* phys addr of internal
req data buf */
TW_UINT32 max_simult_reqs; /* max simultaneous requests
supported */
TW_UINT32 max_aens_supported;/* max AEN's supported */
/* AEN handler fields. */
struct tw_cl_event_packet *aen_queue; /* circular queue of AENs from
firmware/CL/OSL */
TW_UINT32 aen_head; /* AEN queue head */
TW_UINT32 aen_tail; /* AEN queue tail */
TW_UINT32 aen_cur_seq_id; /* index of the last event+1 */
TW_UINT32 aen_q_overflow; /* indicates if unretrieved
events were overwritten */
TW_UINT32 aen_q_wrapped; /* indicates if AEN queue ever
wrapped */
TW_UINT16 working_srl; /* driver & firmware negotiated
srl */
TW_UINT16 working_branch; /* branch # of the firmware
that the driver is compatible with */
TW_UINT16 working_build; /* build # of the firmware
that the driver is compatible with */
TW_UINT32 operating_mode; /* base mode/current mode */
TW_INT32 host_intr_pending;/* host intr processing
needed */
TW_INT32 attn_intr_pending;/* attn intr processing
needed */
TW_INT32 cmd_intr_pending;/* cmd intr processing
needed */
TW_INT32 resp_intr_pending;/* resp intr processing
needed */
TW_LOCK_HANDLE gen_lock_handle;/* general purpose lock */
TW_LOCK_HANDLE *gen_lock;/* ptr to general purpose lock */
TW_LOCK_HANDLE io_lock_handle; /* lock held during cmd
submission */
TW_LOCK_HANDLE *io_lock;/* ptr to lock held during cmd
submission */
TW_LOCK_HANDLE intr_lock_handle;/* lock held during
ISR/response intr processing */
TW_LOCK_HANDLE *intr_lock;/* ptr to lock held during ISR/
response intr processing */
#ifdef TW_OSL_CAN_SLEEP
TW_SLEEP_HANDLE sleep_handle; /* handle to co-ordinate sleeps
& wakeups */
#endif /* TW_OSL_CAN_SLEEP */
struct {
TW_UINT32 lock; /* lock state */
TW_TIME timeout; /* time at which the lock will
become available, even if not
explicitly released */
} ioctl_lock; /* lock for use by user applications, for
synchronization between ioctl calls */
#ifdef TW_OSL_DEBUG
struct tw_cli_q_stats q_stats[TW_CLI_Q_COUNT];/* queue statistics */
#endif /* TW_OSL_DEBUG */
};
#pragma pack()
/*
* Queue primitives
*/
#ifdef TW_OSL_DEBUG
#define TW_CLI_Q_INIT(ctlr, q_type) do { \
(ctlr)->q_stats[q_type].cur_len = 0; \
(ctlr)->q_stats[q_type].max_len = 0; \
} while (0)
#define TW_CLI_Q_INSERT(ctlr, q_type) do { \
struct tw_cli_q_stats *q_stats = &((ctlr)->q_stats[q_type]); \
\
if (++(q_stats->cur_len) > q_stats->max_len) \
q_stats->max_len = q_stats->cur_len; \
} while (0)
#define TW_CLI_Q_REMOVE(ctlr, q_type) \
(ctlr)->q_stats[q_type].cur_len--
#else /* TW_OSL_DEBUG */
#define TW_CLI_Q_INIT(ctlr, q_index)
#define TW_CLI_Q_INSERT(ctlr, q_index)
#define TW_CLI_Q_REMOVE(ctlr, q_index)
#endif /* TW_OSL_DEBUG */
/* Initialize a queue of requests. */
static __inline TW_VOID
tw_cli_req_q_init(struct tw_cli_ctlr_context *ctlr, TW_UINT8 q_type)
{
TW_CL_Q_INIT(&(ctlr->req_q_head[q_type]));
TW_CLI_Q_INIT(ctlr, q_type);
}
/* Insert the given request at the head of the given queue (q_type). */
static __inline TW_VOID
tw_cli_req_q_insert_head(struct tw_cli_req_context *req, TW_UINT8 q_type)
{
struct tw_cli_ctlr_context *ctlr = req->ctlr;
#ifdef TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST
if ((q_type == TW_CLI_BUSY_Q) || (q_type == TW_CLI_COMPLETE_Q) ||
((q_type == TW_CLI_PENDING_Q) &&
(!(req->flags & TW_CLI_REQ_FLAGS_INTERNAL))))
return;
#endif /* TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST */
tw_osl_get_lock(ctlr->ctlr_handle, ctlr->gen_lock);
TW_CL_Q_INSERT_HEAD(&(ctlr->req_q_head[q_type]), &(req->link));
TW_CLI_Q_INSERT(ctlr, q_type);
tw_osl_free_lock(ctlr->ctlr_handle, ctlr->gen_lock);
}
/* Insert the given request at the tail of the given queue (q_type). */
static __inline TW_VOID
tw_cli_req_q_insert_tail(struct tw_cli_req_context *req, TW_UINT8 q_type)
{
struct tw_cli_ctlr_context *ctlr = req->ctlr;
#ifdef TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST
if ((q_type == TW_CLI_BUSY_Q) || (q_type == TW_CLI_COMPLETE_Q) ||
((q_type == TW_CLI_PENDING_Q) &&
(!(req->flags & TW_CLI_REQ_FLAGS_INTERNAL))))
return;
if ((q_type == TW_CLI_FREE_Q) &&
(!(req->flags & TW_CLI_REQ_FLAGS_INTERNAL))) {
ctlr->free_req_ids[ctlr->free_req_tail] = req->request_id;
ctlr->busy_reqs[req->request_id] = TW_CL_NULL;
ctlr->free_req_tail = (ctlr->free_req_tail + 1) %
(ctlr->max_simult_reqs - 1);
ctlr->num_free_req_ids++;
return;
}
#endif /* TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST */
tw_osl_get_lock(ctlr->ctlr_handle, ctlr->gen_lock);
TW_CL_Q_INSERT_TAIL(&(ctlr->req_q_head[q_type]), &(req->link));
TW_CLI_Q_INSERT(ctlr, q_type);
tw_osl_free_lock(ctlr->ctlr_handle, ctlr->gen_lock);
}
/* Remove and return the request at the head of the given queue (q_type). */
static __inline struct tw_cli_req_context *
tw_cli_req_q_remove_head(struct tw_cli_ctlr_context *ctlr, TW_UINT8 q_type)
{
struct tw_cli_req_context *req = TW_CL_NULL;
struct tw_cl_link *link;
#ifdef TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST
if ((q_type == TW_CLI_BUSY_Q) || (q_type == TW_CLI_COMPLETE_Q))
return(req);
#endif /* TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST */
tw_osl_get_lock(ctlr->ctlr_handle, ctlr->gen_lock);
if ((link = TW_CL_Q_FIRST_ITEM(&(ctlr->req_q_head[q_type]))) !=
TW_CL_NULL) {
req = TW_CL_STRUCT_HEAD(link,
struct tw_cli_req_context, link);
TW_CL_Q_REMOVE_ITEM(&(ctlr->req_q_head[q_type]), &(req->link));
TW_CLI_Q_REMOVE(ctlr, q_type);
}
tw_osl_free_lock(ctlr->ctlr_handle, ctlr->gen_lock);
return(req);
}
/* Remove the given request from the given queue (q_type). */
static __inline TW_VOID
tw_cli_req_q_remove_item(struct tw_cli_req_context *req, TW_UINT8 q_type)
{
struct tw_cli_ctlr_context *ctlr = req->ctlr;
#ifdef TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST
if ((q_type == TW_CLI_BUSY_Q) || (q_type == TW_CLI_COMPLETE_Q) ||
((q_type == TW_CLI_PENDING_Q) &&
(!(req->flags & TW_CLI_REQ_FLAGS_INTERNAL))))
return;
#endif /* TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST */
tw_osl_get_lock(ctlr->ctlr_handle, ctlr->gen_lock);
TW_CL_Q_REMOVE_ITEM(&(ctlr->req_q_head[q_type]), &(req->link));
TW_CLI_Q_REMOVE(ctlr, q_type);
tw_osl_free_lock(ctlr->ctlr_handle, ctlr->gen_lock);
}
/* Create an event packet for an event/error posted by the controller. */
#define tw_cli_create_ctlr_event(ctlr, event_src, cmd_hdr) do { \
TW_UINT8 severity = \
GET_SEVERITY((cmd_hdr)->status_block.res__severity); \
\
tw_cl_create_event(ctlr->ctlr_handle, TW_CL_TRUE, event_src, \
(cmd_hdr)->status_block.error, \
severity, \
tw_cli_severity_string_table[severity], \
(cmd_hdr)->err_specific_desc + \
tw_osl_strlen((cmd_hdr)->err_specific_desc) + 1, \
(cmd_hdr)->err_specific_desc); \
/* Print 18 bytes of sense information. */ \
tw_cli_dbg_printf(2, ctlr->ctlr_handle, \
tw_osl_cur_func(), \
"sense info: %x %x %x %x %x %x %x %x %x " \
"%x %x %x %x %x %x %x %x %x", \
(cmd_hdr)->sense_data[0], (cmd_hdr)->sense_data[1], \
(cmd_hdr)->sense_data[2], (cmd_hdr)->sense_data[3], \
(cmd_hdr)->sense_data[4], (cmd_hdr)->sense_data[5], \
(cmd_hdr)->sense_data[6], (cmd_hdr)->sense_data[7], \
(cmd_hdr)->sense_data[8], (cmd_hdr)->sense_data[9], \
(cmd_hdr)->sense_data[10], (cmd_hdr)->sense_data[11], \
(cmd_hdr)->sense_data[12], (cmd_hdr)->sense_data[13], \
(cmd_hdr)->sense_data[14], (cmd_hdr)->sense_data[15], \
(cmd_hdr)->sense_data[16], (cmd_hdr)->sense_data[17]); \
} while (0)
#endif /* TW_CL_H */

210
sys/dev/twa/tw_cl_externs.h Normal file
View File

@ -0,0 +1,210 @@
/*
* 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
*/
#ifndef TW_CL_EXTERNS_H
#define TW_CL_EXTERNS_H
/*
* Data structures and functions global to the Common Layer.
*/
extern TW_INT8 tw_cli_fw_img[];
extern TW_INT32 tw_cli_fw_img_size;
extern TW_INT8 *tw_cli_severity_string_table[];
#ifdef TW_OSL_FLASH_FIRMWARE
/* Functions in tw_cl_init.c */
/* Flash bundled firmware image onto controller. */
extern TW_INT32 tw_cli_flash_firmware(struct tw_cli_ctlr_context *ctlr);
/* Hard reset the controller. */
extern TW_INT32 tw_cli_hard_reset(struct tw_cli_ctlr_context *ctlr);
#endif /* TW_OSL_FLASH_FIRMWARE */
/* Do controller initialization. */
extern TW_INT32 tw_cli_start_ctlr(struct tw_cli_ctlr_context *ctlr);
/* Establish a logical connection with the firmware on the controller. */
extern 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);
/* Functions in tw_cl_io.c */
/* Submit a command packet to the firmware on the controller. */
extern TW_INT32 tw_cli_submit_cmd(struct tw_cli_req_context *req);
/* Get a firmware parameter. */
extern TW_INT32 tw_cli_get_param(struct tw_cli_ctlr_context *ctlr,
TW_INT32 table_id, TW_INT32 parameter_id, TW_VOID *param_data,
TW_INT32 size, TW_VOID (* callback)(struct tw_cli_req_context *req));
/* Set a firmware parameter. */
extern TW_INT32 tw_cli_set_param(struct tw_cli_ctlr_context *ctlr,
TW_INT32 table_id, TW_INT32 param_id, TW_INT32 param_size,
TW_VOID *data, TW_VOID (* callback)(struct tw_cli_req_context *req));
/* Submit a command to the firmware and poll for completion. */
extern TW_INT32 tw_cli_submit_and_poll_request(struct tw_cli_req_context *req,
TW_UINT32 timeout);
/* Soft reset the controller. */
extern TW_INT32 tw_cli_soft_reset(struct tw_cli_ctlr_context *ctlr);
/* Send down a SCSI command to the firmware (usually, an internal Req Sense. */
extern TW_INT32 tw_cli_send_scsi_cmd(struct tw_cli_req_context *req,
TW_INT32 cmd);
/* Get an AEN from the firmware (by sending down a Req Sense). */
extern TW_INT32 tw_cli_get_aen(struct tw_cli_ctlr_context *ctlr);
/* Fill in the scatter/gather list. */
extern TW_VOID tw_cli_fill_sg_list(struct tw_cli_ctlr_context *ctlr,
TW_VOID *sgl_src, TW_VOID *sgl_dest, TW_INT32 num_sgl_entries);
/* Functions in tw_cl_intr.c */
/* Process a host interrupt. */
extern TW_VOID tw_cli_process_host_intr(struct tw_cli_ctlr_context *ctlr);
/* Process an attention interrupt. */
extern TW_VOID tw_cli_process_attn_intr(struct tw_cli_ctlr_context *ctlr);
/* Process a command interrupt. */
extern TW_VOID tw_cli_process_cmd_intr(struct tw_cli_ctlr_context *ctlr);
/* Process a response interrupt from the controller. */
extern TW_INT32 tw_cli_process_resp_intr(struct tw_cli_ctlr_context *ctlr);
/* Submit any requests in the pending queue to the firmware. */
extern TW_INT32 tw_cli_submit_pending_queue(struct tw_cli_ctlr_context *ctlr);
/* Process all requests in the complete queue. */
extern TW_VOID tw_cli_process_complete_queue(struct tw_cli_ctlr_context *ctlr);
/* CL internal callback for SCSI/fw passthru requests. */
extern TW_VOID tw_cli_complete_io(struct tw_cli_req_context *req);
/* Completion routine for SCSI requests. */
extern TW_VOID tw_cli_scsi_complete(struct tw_cli_req_context *req);
/* Callback for get/set param requests. */
extern TW_VOID tw_cli_param_callback(struct tw_cli_req_context *req);
/* Callback for Req Sense commands to get AEN's. */
extern TW_VOID tw_cli_aen_callback(struct tw_cli_req_context *req);
/* Decide what to do with a retrieved AEN. */
extern TW_UINT16 tw_cli_manage_aen(struct tw_cli_ctlr_context *ctlr,
struct tw_cli_req_context *req);
/* Enable controller interrupts. */
extern TW_VOID
tw_cli_enable_interrupts(struct tw_cli_ctlr_context *ctlr_handle);
/* Disable controller interrupts. */
extern TW_VOID
tw_cli_disable_interrupts(struct tw_cli_ctlr_context *ctlr_handle);
/* Functions in tw_cl_misc.c */
/* Print if dbg_level is appropriate (by calling OS Layer). */
extern TW_VOID tw_cli_dbg_printf(TW_UINT8 dbg_level,
struct tw_cl_ctlr_handle *ctlr_handle, const TW_INT8 *cur_func,
TW_INT8 *fmt, ...);
/* Describe meaning of each set bit in the given register. */
extern TW_INT8 *tw_cli_describe_bits(TW_UINT32 reg, TW_INT8 *str);
/* Complete all requests in the complete queue with a RESET status. */
extern TW_VOID tw_cli_drain_complete_queue(struct tw_cli_ctlr_context *ctlr);
/* Complete all requests in the busy queue with a RESET status. */
extern TW_VOID tw_cli_drain_busy_queue(struct tw_cli_ctlr_context *ctlr);
/* Complete all requests in the pending queue with a RESET status. */
extern TW_VOID tw_cli_drain_pending_queue(struct tw_cli_ctlr_context *ctlr);
/* Drain the controller response queue. */
extern TW_INT32 tw_cli_drain_response_queue(struct tw_cli_ctlr_context *ctlr);
/* Drain the controller AEN queue. */
extern TW_INT32 tw_cli_drain_aen_queue(struct tw_cli_ctlr_context *ctlr);
/* Determine if a given AEN has been posted by the firmware. */
extern TW_INT32 tw_cli_find_aen(struct tw_cli_ctlr_context *ctlr,
TW_UINT16 aen_code);
/* Poll for a given status to show up in the firmware status register. */
extern TW_INT32 tw_cli_poll_status(struct tw_cli_ctlr_context *ctlr,
TW_UINT32 status, TW_UINT32 timeout);
/* Get a free CL internal request context packet. */
extern struct tw_cli_req_context *
tw_cli_get_request(struct tw_cli_ctlr_context *ctlr
#ifdef TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST
, struct tw_cl_req_packet *req_pkt
#endif /* TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST */
);
/* Notify OSL of controller info (fw/BIOS versions, etc.). */
extern TW_VOID tw_cli_notify_ctlr_info(struct tw_cli_ctlr_context *ctlr);
/* Make sure that the firmware status register reports a proper status. */
extern TW_INT32 tw_cli_check_ctlr_state(struct tw_cli_ctlr_context *ctlr,
TW_UINT32 status_reg);
#endif /* TW_CL_EXTERNS_H */

425
sys/dev/twa/tw_cl_fwif.h Normal file
View File

@ -0,0 +1,425 @@
/*
* 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
*/
#ifndef TW_CL_FWIF_H
#define TW_CL_FWIF_H
/*
* Macros and data structures for interfacing with the firmware.
*/
/* Register offsets from base address. */
#define TWA_CONTROL_REGISTER_OFFSET 0x0
#define TWA_STATUS_REGISTER_OFFSET 0x4
#define TWA_COMMAND_QUEUE_OFFSET 0x8
#define TWA_RESPONSE_QUEUE_OFFSET 0xC
#define TWA_COMMAND_QUEUE_OFFSET_LOW 0x20
#define TWA_COMMAND_QUEUE_OFFSET_HIGH 0x24
/* Control register bit definitions. */
#define TWA_CONTROL_CLEAR_SBUF_WRITE_ERROR 0x00000008
#define TWA_CONTROL_ISSUE_HOST_INTERRUPT 0x00000020
#define TWA_CONTROL_DISABLE_INTERRUPTS 0x00000040
#define TWA_CONTROL_ENABLE_INTERRUPTS 0x00000080
#define TWA_CONTROL_ISSUE_SOFT_RESET 0x00000100
#define TWA_CONTROL_UNMASK_RESPONSE_INTERRUPT 0x00004000
#define TWA_CONTROL_UNMASK_COMMAND_INTERRUPT 0x00008000
#define TWA_CONTROL_MASK_RESPONSE_INTERRUPT 0x00010000
#define TWA_CONTROL_MASK_COMMAND_INTERRUPT 0x00020000
#define TWA_CONTROL_CLEAR_ATTENTION_INTERRUPT 0x00040000
#define TWA_CONTROL_CLEAR_HOST_INTERRUPT 0x00080000
#define TWA_CONTROL_CLEAR_PCI_ABORT 0x00100000
#define TWA_CONTROL_CLEAR_QUEUE_ERROR 0x00400000
#define TWA_CONTROL_CLEAR_PARITY_ERROR 0x00800000
/* Status register bit definitions. */
#define TWA_STATUS_ROM_BIOS_IN_SBUF 0x00000002
#define TWA_STATUS_SBUF_WRITE_ERROR 0x00000008
#define TWA_STATUS_COMMAND_QUEUE_EMPTY 0x00001000
#define TWA_STATUS_MICROCONTROLLER_READY 0x00002000
#define TWA_STATUS_RESPONSE_QUEUE_EMPTY 0x00004000
#define TWA_STATUS_COMMAND_QUEUE_FULL 0x00008000
#define TWA_STATUS_RESPONSE_INTERRUPT 0x00010000
#define TWA_STATUS_COMMAND_INTERRUPT 0x00020000
#define TWA_STATUS_ATTENTION_INTERRUPT 0x00040000
#define TWA_STATUS_HOST_INTERRUPT 0x00080000
#define TWA_STATUS_PCI_ABORT_INTERRUPT 0x00100000
#define TWA_STATUS_MICROCONTROLLER_ERROR 0x00200000
#define TWA_STATUS_QUEUE_ERROR_INTERRUPT 0x00400000
#define TWA_STATUS_PCI_PARITY_ERROR_INTERRUPT 0x00800000
#define TWA_STATUS_MINOR_VERSION_MASK 0x0F000000
#define TWA_STATUS_MAJOR_VERSION_MASK 0xF0000000
#define TWA_STATUS_EXPECTED_BITS 0x00002000
#define TWA_STATUS_UNEXPECTED_BITS 0x00F00000
/* PCI related defines. */
#define TWA_IO_CONFIG_REG 0x10
#define TWA_PCI_CONFIG_CLEAR_PARITY_ERROR 0xc100
#define TWA_PCI_CONFIG_CLEAR_PCI_ABORT 0x2000
/* Command packet opcodes. */
#define TWA_FW_CMD_NOP 0x00
#define TWA_FW_CMD_INIT_CONNECTION 0x01
#define TWA_FW_CMD_READ 0x02
#define TWA_FW_CMD_WRITE 0x03
#define TWA_FW_CMD_READVERIFY 0x04
#define TWA_FW_CMD_VERIFY 0x05
#define TWA_FW_CMD_ZEROUNIT 0x08
#define TWA_FW_CMD_REPLACEUNIT 0x09
#define TWA_FW_CMD_HOTSWAP 0x0A
#define TWA_FW_CMD_SELFTESTS 0x0B
#define TWA_FW_CMD_SYNC_PARAM 0x0C
#define TWA_FW_CMD_REORDER_UNITS 0x0D
#define TWA_FW_CMD_EXECUTE_SCSI 0x10
#define TWA_FW_CMD_ATA_PASSTHROUGH 0x11
#define TWA_FW_CMD_GET_PARAM 0x12
#define TWA_FW_CMD_SET_PARAM 0x13
#define TWA_FW_CMD_CREATEUNIT 0x14
#define TWA_FW_CMD_DELETEUNIT 0x15
#define TWA_FW_CMD_DOWNLOAD_FIRMWARE 0x16
#define TWA_FW_CMD_REBUILDUNIT 0x17
#define TWA_FW_CMD_POWER_MANAGEMENT 0x18
#define TWA_FW_CMD_REMOTE_PRINT 0x1B
#define TWA_FW_CMD_HARD_RESET_FIRMWARE 0x1C
#define TWA_FW_CMD_DEBUG 0x1D
#define TWA_FW_CMD_DIAGNOSTICS 0x1F
/* Misc defines. */
#define TWA_BUNDLED_FW_VERSION_STRING "2.06.00.009"
#define TWA_SHUTDOWN_MESSAGE_CREDITS 0x001
#define TWA_64BIT_SG_ADDRESSES 0x00000001
#define TWA_EXTENDED_INIT_CONNECT 0x00000002
#define TWA_BASE_MODE 1
#define TWA_BASE_FW_SRL 24
#define TWA_BASE_FW_BRANCH 0
#define TWA_BASE_FW_BUILD 1
#define TWA_CURRENT_FW_SRL 28
#define TWA_CURRENT_FW_BRANCH 4
#define TWA_CURRENT_FW_BUILD 9
#define TWA_MULTI_LUN_FW_SRL 28
#define TWA_9000_ARCH_ID 0x5 /* 9000 series controllers */
#define TWA_CTLR_FW_SAME_OR_NEWER 0x00000001
#define TWA_CTLR_FW_COMPATIBLE 0x00000002
#define TWA_BUNDLED_FW_SAFE_TO_FLASH 0x00000004
#define TWA_CTLR_FW_RECOMMENDS_FLASH 0x00000008
#define TWA_SENSE_DATA_LENGTH 18
/*
* All SG addresses and DMA'able memory allocated by the OSL should be
* TWA_ALIGNMENT bytes aligned, and have a size that is a multiple of
* TWA_SG_ELEMENT_SIZE_FACTOR.
*/
#define TWA_ALIGNMENT 0x4
#define TWA_SG_ELEMENT_SIZE_FACTOR 512
/*
* Some errors of interest (in cmd_hdr->status_block.error) when a command
* is completed by the firmware with a bad status.
*/
#define TWA_ERROR_LOGICAL_UNIT_NOT_SUPPORTED 0x010a
#define TWA_ERROR_UNIT_OFFLINE 0x0128
#define TWA_ERROR_MORE_DATA 0x0231
/* AEN codes of interest. */
#define TWA_AEN_QUEUE_EMPTY 0x00
#define TWA_AEN_SOFT_RESET 0x01
#define TWA_AEN_SYNC_TIME_WITH_HOST 0x31
/* Table #'s and id's of parameters of interest in firmware's param table. */
#define TWA_PARAM_VERSION_TABLE 0x0402
#define TWA_PARAM_VERSION_FW 3 /* firmware version [16] */
#define TWA_PARAM_VERSION_BIOS 4 /* BIOSs version [16] */
#define TWA_PARAM_CONTROLLER_TABLE 0x0403
#define TWA_PARAM_CONTROLLER_PORT_COUNT 3 /* number of ports [1] */
#define TWA_PARAM_TIME_TABLE 0x40A
#define TWA_PARAM_TIME_SCHED_TIME 0x3
#define TWA_9K_PARAM_DESCRIPTOR 0x8000
#pragma pack(1)
/* 7000 structures. */
struct tw_cl_command_init_connect {
TW_UINT8 res1__opcode; /* 3:5 */
TW_UINT8 size;
TW_UINT8 request_id;
TW_UINT8 res2;
TW_UINT8 status;
TW_UINT8 flags;
TW_UINT16 message_credits;
TW_UINT32 features;
TW_UINT16 fw_srl;
TW_UINT16 fw_arch_id;
TW_UINT16 fw_branch;
TW_UINT16 fw_build;
TW_UINT32 result;
};
/* Structure for downloading firmware onto the controller. */
struct tw_cl_command_download_firmware {
TW_UINT8 sgl_off__opcode;/* 3:5 */
TW_UINT8 size;
TW_UINT8 request_id;
TW_UINT8 unit;
TW_UINT8 status;
TW_UINT8 flags;
TW_UINT16 param;
TW_UINT8 sgl[1];
};
/* Structure for hard resetting the controller. */
struct tw_cl_command_reset_firmware {
TW_UINT8 res1__opcode; /* 3:5 */
TW_UINT8 size;
TW_UINT8 request_id;
TW_UINT8 unit;
TW_UINT8 status;
TW_UINT8 flags;
TW_UINT8 res2;
TW_UINT8 param;
};
/* Structure for sending get/set param commands. */
struct tw_cl_command_param {
TW_UINT8 sgl_off__opcode;/* 3:5 */
TW_UINT8 size;
TW_UINT8 request_id;
TW_UINT8 host_id__unit; /* 4:4 */
TW_UINT8 status;
TW_UINT8 flags;
TW_UINT16 param_count;
TW_UINT8 sgl[1];
};
/* Generic command packet. */
struct tw_cl_command_generic {
TW_UINT8 sgl_off__opcode;/* 3:5 */
TW_UINT8 size;
TW_UINT8 request_id;
TW_UINT8 host_id__unit; /* 4:4 */
TW_UINT8 status;
TW_UINT8 flags;
TW_UINT16 count; /* block cnt, parameter cnt, message credits */
};
/* Command packet header. */
struct tw_cl_command_header {
TW_UINT8 sense_data[TWA_SENSE_DATA_LENGTH];
struct {
TW_INT8 reserved[4];
TW_UINT16 error;
TW_UINT8 padding;
TW_UINT8 res__severity; /* 5:3 */
} status_block;
TW_UINT8 err_specific_desc[98];
struct {
TW_UINT8 size_header;
TW_UINT16 reserved;
TW_UINT8 size_sense;
} header_desc;
};
/* 7000 Command packet. */
union tw_cl_command_7k {
struct tw_cl_command_init_connect init_connect;
struct tw_cl_command_download_firmware download_fw;
struct tw_cl_command_reset_firmware reset_fw;
struct tw_cl_command_param param;
struct tw_cl_command_generic generic;
TW_UINT8 padding[1024 - sizeof(struct tw_cl_command_header)];
};
/* 9000 Command Packet. */
struct tw_cl_command_9k {
TW_UINT8 res__opcode; /* 3:5 */
TW_UINT8 unit;
TW_UINT16 lun_l4__req_id; /* 4:12 */
TW_UINT8 status;
TW_UINT8 sgl_offset; /* offset (in bytes) to sg_list, from the
end of sgl_entries */
TW_UINT16 lun_h4__sgl_entries;
TW_UINT8 cdb[16];
TW_UINT8 sg_list[872];/* total struct size =
1024-sizeof(cmd_hdr) */
};
/* Full command packet. */
struct tw_cl_command_packet {
struct tw_cl_command_header cmd_hdr;
union {
union tw_cl_command_7k cmd_pkt_7k;
struct tw_cl_command_9k cmd_pkt_9k;
} command;
};
/* Structure describing payload for get/set param commands. */
struct tw_cl_param_9k {
TW_UINT16 table_id;
TW_UINT8 parameter_id;
TW_UINT8 reserved;
TW_UINT16 parameter_size_bytes;
TW_UINT16 parameter_actual_size_bytes;
TW_UINT8 data[1];
};
#pragma pack()
/* Functions to read from, and write to registers */
#define TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle, value) \
tw_osl_write_reg(ctlr_handle, TWA_CONTROL_REGISTER_OFFSET, value, 4)
#define TW_CLI_READ_STATUS_REGISTER(ctlr_handle) \
tw_osl_read_reg(ctlr_handle, TWA_STATUS_REGISTER_OFFSET, 4)
#define TW_CLI_WRITE_COMMAND_QUEUE(ctlr_handle, value) do { \
if (ctlr->flags & TW_CL_64BIT_ADDRESSES) { \
/* First write the low 4 bytes, then the high 4. */ \
tw_osl_write_reg(ctlr_handle, TWA_COMMAND_QUEUE_OFFSET_LOW, \
(TW_UINT32)(value), 4); \
tw_osl_write_reg(ctlr_handle, TWA_COMMAND_QUEUE_OFFSET_HIGH,\
(TW_UINT32)(((TW_UINT64)value)>>32), 4); \
} else \
tw_osl_write_reg(ctlr_handle, TWA_COMMAND_QUEUE_OFFSET, \
(TW_UINT32)(value), 4); \
} while (0)
#define TW_CLI_READ_RESPONSE_QUEUE(ctlr_handle) \
tw_osl_read_reg(ctlr_handle, TWA_RESPONSE_QUEUE_OFFSET, 4)
#define TW_CLI_SOFT_RESET(ctlr) \
TW_CLI_WRITE_CONTROL_REGISTER(ctlr, \
TWA_CONTROL_ISSUE_SOFT_RESET | \
TWA_CONTROL_CLEAR_HOST_INTERRUPT | \
TWA_CONTROL_CLEAR_ATTENTION_INTERRUPT | \
TWA_CONTROL_MASK_COMMAND_INTERRUPT | \
TWA_CONTROL_MASK_RESPONSE_INTERRUPT | \
TWA_CONTROL_DISABLE_INTERRUPTS)
/* Detect inconsistencies in the status register. */
#define TW_CLI_STATUS_ERRORS(x) \
((x & TWA_STATUS_UNEXPECTED_BITS) && \
(x & TWA_STATUS_MICROCONTROLLER_READY))
/*
* Functions for making transparent, the bit fields in firmware
* interface structures.
*/
#define BUILD_SGL_OFF__OPCODE(sgl_off, opcode) \
((sgl_off << 5) & 0xE0) | (opcode & 0x1F) /* 3:5 */
#define BUILD_RES__OPCODE(res, opcode) \
((res << 5) & 0xE0) | (opcode & 0x1F) /* 3:5 */
#define BUILD_HOST_ID__UNIT(host_id, unit) \
((host_id << 4) & 0xF0) | (unit & 0xF) /* 4:4 */
#define BUILD_RES__SEVERITY(res, severity) \
((res << 3) & 0xF8) | (severity & 0x7) /* 5:3 */
#define BUILD_LUN_L4__REQ_ID(lun, req_id) \
(((lun << 12) & 0xF000) | (req_id & 0xFFF)) /* 4:12 */
#define BUILD_LUN_H4__SGL_ENTRIES(lun, sgl_entries) \
(((lun << 8) & 0xF000) | (sgl_entries & 0xFFF)) /* 4:12 */
#define GET_OPCODE(sgl_off__opcode) \
(sgl_off__opcode & 0x1F) /* 3:5 */
#define GET_SGL_OFF(sgl_off__opcode) \
((sgl_off__opcode >> 5) & 0x7) /* 3:5 */
#define GET_UNIT(host_id__unit) \
(host_id__unit & 0xF) /* 4:4 */
#define GET_HOST_ID(host_id__unit) \
((host_id__unit >> 4) & 0xF) /* 4:4 */
#define GET_SEVERITY(res__severity) \
(res__severity & 0x7) /* 5:3 */
#define GET_RESP_ID(undef2__resp_id__undef1) \
((undef2__resp_id__undef1 >> 4) & 0xFF) /* 20:8:4 */
#define GET_REQ_ID(lun_l4__req_id) \
(lun_l4__req_id & 0xFFF) /* 4:12 */
#define GET_LUN_L4(lun_l4__req_id) \
((lun_l4__req_id >> 12) & 0xF) /* 4:12 */
#define GET_SGL_ENTRIES(lun_h4__sgl_entries) \
(lun_h4__sgl_entries & 0xFFF) /* 4:12 */
#define GET_LUN_H4(lun_h4__sgl_entries) \
((lun_h4__sgl_entries >> 12) & 0xF) /* 4:12 */
#endif /* TW_CL_FWIF_H */

26802
sys/dev/twa/tw_cl_fwimg.c Normal file

File diff suppressed because it is too large Load Diff

1104
sys/dev/twa/tw_cl_init.c Normal file

File diff suppressed because it is too large Load Diff

826
sys/dev/twa/tw_cl_intr.c Normal file
View File

@ -0,0 +1,826 @@
/*
* 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 interrupt handling 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: twa_interrupt
* Description: Interrupt handler. Determines the kind of interrupt,
* and returns TW_CL_TRUE if it recognizes the interrupt.
*
* Input: ctlr_handle -- controller handle
* Output: None
* Return value: TW_CL_TRUE -- interrupt recognized
* TW_CL_FALSE-- interrupt not recognized
*/
TW_INT32
tw_cl_interrupt(struct tw_cl_ctlr_handle *ctlr_handle)
{
struct tw_cli_ctlr_context *ctlr =
(struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt);
TW_UINT32 status_reg;
TW_INT32 rc = TW_CL_FALSE;
tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), "entered");
/*
* Serialize access to this function so multiple threads don't try to
* do the same thing (such as clearing interrupt bits).
*/
tw_osl_get_lock(ctlr_handle, ctlr->intr_lock);
/* Read the status register to determine the type of interrupt. */
status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr_handle);
if (tw_cli_check_ctlr_state(ctlr, status_reg))
goto out;
/* Clear the interrupt. */
if (status_reg & TWA_STATUS_HOST_INTERRUPT) {
tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(),
"Host interrupt");
TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle,
TWA_CONTROL_CLEAR_HOST_INTERRUPT);
ctlr->host_intr_pending = 0; /* we don't use this */
rc |= TW_CL_FALSE; /* don't request for a deferred isr call */
}
if (status_reg & TWA_STATUS_ATTENTION_INTERRUPT) {
tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(),
"Attention interrupt");
TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle,
TWA_CONTROL_CLEAR_ATTENTION_INTERRUPT);
ctlr->attn_intr_pending = 1;
rc |= TW_CL_TRUE; /* request for a deferred isr call */
}
if (status_reg & TWA_STATUS_COMMAND_INTERRUPT) {
tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(),
"Command interrupt");
TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle,
TWA_CONTROL_MASK_COMMAND_INTERRUPT);
ctlr->cmd_intr_pending = 1;
rc |= TW_CL_TRUE; /* request for a deferred isr call */
}
if (status_reg & TWA_STATUS_RESPONSE_INTERRUPT) {
tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(),
"Response interrupt");
TW_CLI_WRITE_CONTROL_REGISTER(ctlr_handle,
TWA_CONTROL_MASK_RESPONSE_INTERRUPT);
ctlr->resp_intr_pending = 1;
rc |= TW_CL_TRUE; /* request for a deferred isr call */
}
out:
tw_osl_free_lock(ctlr_handle, ctlr->intr_lock);
return(rc);
}
/*
* Function name: tw_cl_deferred_interrupt
* Description: Deferred interrupt handler. Does most of the processing
* related to an interrupt.
*
* Input: ctlr_handle -- controller handle
* Output: None
* Return value: None
*/
TW_VOID
tw_cl_deferred_interrupt(struct tw_cl_ctlr_handle *ctlr_handle)
{
struct tw_cli_ctlr_context *ctlr =
(struct tw_cli_ctlr_context *)(ctlr_handle->cl_ctlr_ctxt);
tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(), "entered");
/* Dispatch based on the kind of interrupt. */
if (ctlr->host_intr_pending) {
tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(),
"Processing Host interrupt");
ctlr->host_intr_pending = 0;
tw_cli_process_host_intr(ctlr);
}
if (ctlr->attn_intr_pending) {
tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(),
"Processing Attention interrupt");
ctlr->attn_intr_pending = 0;
tw_cli_process_attn_intr(ctlr);
}
if (ctlr->cmd_intr_pending) {
tw_cli_dbg_printf(6, ctlr_handle, tw_osl_cur_func(),
"Processing Command interrupt");
ctlr->cmd_intr_pending = 0;
tw_cli_process_cmd_intr(ctlr);
}
if (ctlr->resp_intr_pending) {
tw_cli_dbg_printf(10, ctlr_handle, tw_osl_cur_func(),
"Processing Response interrupt");
ctlr->resp_intr_pending = 0;
tw_cli_process_resp_intr(ctlr);
}
}
/*
* Function name: tw_cli_process_host_intr
* Description: This function gets called if we triggered an interrupt.
* We don't use it as of now.
*
* Input: ctlr -- ptr to CL internal ctlr context
* Output: None
* Return value: None
*/
TW_VOID
tw_cli_process_host_intr(struct tw_cli_ctlr_context *ctlr)
{
tw_cli_dbg_printf(6, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
}
/*
* Function name: tw_cli_process_attn_intr
* Description: This function gets called if the fw posted an AEN
* (Asynchronous Event Notification). It fetches
* all the AEN's that the fw might have posted.
*
* Input: ctlr -- ptr to CL internal ctlr context
* Output: None
* Return value: None
*/
TW_VOID
tw_cli_process_attn_intr(struct tw_cli_ctlr_context *ctlr)
{
TW_INT32 error;
tw_cli_dbg_printf(6, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
if ((error = tw_cli_get_aen(ctlr))) {
/*
* If the driver is already in the process of retrieveing AEN's,
* we will be returned TW_OSL_EBUSY. In this case,
* tw_cli_param_callback or tw_cli_aen_callback will eventually
* retrieve the AEN this attention interrupt is for. So, we
* don't need to print the failure.
*/
if (error != TW_OSL_EBUSY)
tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1200, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"Failed to fetch AEN",
"error = %d", error);
}
}
/*
* Function name: tw_cli_process_cmd_intr
* Description: This function gets called if we hit a queue full
* condition earlier, and the fw is now ready for
* new cmds. Submits any pending requests.
*
* Input: ctlr -- ptr to CL internal ctlr context
* Output: None
* Return value: None
*/
TW_VOID
tw_cli_process_cmd_intr(struct tw_cli_ctlr_context *ctlr)
{
tw_cli_dbg_printf(6, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
/*
* Let the OS Layer submit any requests in its pending queue,
* if it has one.
*/
tw_osl_ctlr_ready(ctlr->ctlr_handle);
/* Start any requests that might be in the pending queue. */
tw_cli_submit_pending_queue(ctlr);
/*
* If tw_cli_submit_pending_queue was unsuccessful due to a "cmd queue
* full" condition, cmd_intr will already have been unmasked by
* tw_cli_submit_cmd. We don't need to do it again... simply return.
*/
}
/*
* Function name: tw_cli_process_resp_intr
* Description: Looks for cmd completions from fw; queues cmds completed
* by fw into complete queue.
*
* Input: ctlr -- ptr to CL internal ctlr context
* Output: None
* Return value: 0 -- no ctlr error
* non-zero-- ctlr error
*/
TW_INT32
tw_cli_process_resp_intr(struct tw_cli_ctlr_context *ctlr)
{
TW_UINT32 resp;
struct tw_cli_req_context *req;
TW_INT32 error;
TW_UINT32 status_reg;
tw_cli_dbg_printf(10, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
/* Serialize access to the controller response queue. */
tw_osl_get_lock(ctlr->ctlr_handle, ctlr->intr_lock);
for (;;) {
status_reg = TW_CLI_READ_STATUS_REGISTER(ctlr->ctlr_handle);
if ((error = tw_cli_check_ctlr_state(ctlr, status_reg)))
break;
if (status_reg & TWA_STATUS_RESPONSE_QUEUE_EMPTY) {
tw_cli_dbg_printf(7, ctlr->ctlr_handle,
tw_osl_cur_func(), "Response queue empty");
break;
}
/* Response queue is not empty. */
resp = TW_CLI_READ_RESPONSE_QUEUE(ctlr->ctlr_handle);
#ifdef TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST
if (GET_RESP_ID(resp) >= 1)
req = ctlr->busy_reqs[GET_RESP_ID(resp)];
else
#endif /* TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST */
{
req = &(ctlr->req_ctxt_buf[GET_RESP_ID(resp)]);
}
if (req->state != TW_CLI_REQ_STATE_BUSY) {
tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1201, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"Unposted command completed!!",
"request = %p, status = %d",
req, req->state);
#ifdef TW_OSL_DEBUG
tw_cl_print_ctlr_stats(ctlr->ctlr_handle);
#endif /* TW_OSL_DEBUG */
tw_osl_free_lock(ctlr->ctlr_handle, ctlr->intr_lock);
tw_cl_reset_ctlr(ctlr->ctlr_handle);
return(TW_OSL_EIO);
}
/*
* Remove the request from the busy queue, mark it as complete,
* and enqueue it in the complete queue.
*/
tw_cli_req_q_remove_item(req, TW_CLI_BUSY_Q);
req->state = TW_CLI_REQ_STATE_COMPLETE;
tw_cli_req_q_insert_tail(req, TW_CLI_COMPLETE_Q);
#ifdef TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST
/* Call the CL internal callback, if there's one. */
if (req->tw_cli_callback)
req->tw_cli_callback(req);
#endif /* TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST */
}
/* Unmask the response interrupt. */
TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle,
TWA_CONTROL_UNMASK_RESPONSE_INTERRUPT);
tw_osl_free_lock(ctlr->ctlr_handle, ctlr->intr_lock);
#ifndef TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST
/* Complete this, and other requests in the complete queue. */
tw_cli_process_complete_queue(ctlr);
#endif /* TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST */
return(error);
}
/*
* Function name: tw_cli_submit_pending_queue
* Description: Kick starts any requests in the pending queue.
*
* Input: ctlr -- ptr to CL internal ctlr context
* Output: None
* Return value: 0 -- all pending requests submitted successfully
* non-zero-- otherwise
*/
TW_INT32
tw_cli_submit_pending_queue(struct tw_cli_ctlr_context *ctlr)
{
struct tw_cli_req_context *req;
TW_INT32 error = TW_OSL_ESUCCESS;
tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
/*
* Pull requests off the pending queue, and submit them.
*/
while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_PENDING_Q)) !=
TW_CL_NULL) {
if ((error = tw_cli_submit_cmd(req))) {
if (error == TW_OSL_EBUSY) {
tw_cli_dbg_printf(2, ctlr->ctlr_handle,
tw_osl_cur_func(),
"Requeueing pending request");
req->state = TW_CLI_REQ_STATE_PENDING;
/*
* Queue the request at the head of the pending
* queue, and break away, so we don't try to
* submit any more requests.
*/
tw_cli_req_q_insert_head(req, TW_CLI_PENDING_Q);
break;
} else {
tw_cl_create_event(ctlr->ctlr_handle,
TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1202, 0x1,
TW_CL_SEVERITY_ERROR_STRING,
"Could not start request "
"in pending queue",
"request = %p, opcode = 0x%x, "
"error = %d", req,
GET_OPCODE(req->cmd_pkt->
command.cmd_pkt_9k.res__opcode),
error);
/*
* Set the appropriate error and call the CL
* internal callback if there's one. If the
* request originator is polling for completion,
* he should be checking req->error to
* determine that the request did not go
* through. The request originators are
* responsible for the clean-up.
*/
req->error_code = error;
req->state = TW_CLI_REQ_STATE_COMPLETE;
if (req->tw_cli_callback)
req->tw_cli_callback(req);
error = TW_OSL_ESUCCESS;
}
}
}
return(error);
}
/*
* Function name: tw_cli_process_complete_queue
* Description: Calls the CL internal callback routine, if any, for
* each request in the complete queue.
*
* Input: ctlr -- ptr to CL internal ctlr context
* Output: None
* Return value: None
*/
TW_VOID
tw_cli_process_complete_queue(struct tw_cli_ctlr_context *ctlr)
{
struct tw_cli_req_context *req;
tw_cli_dbg_printf(10, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
/*
* Pull commands off the completed list, dispatch them appropriately.
*/
while ((req = tw_cli_req_q_remove_head(ctlr, TW_CLI_COMPLETE_Q)) !=
TW_CL_NULL) {
/* Call the CL internal callback, if there's one. */
if (req->tw_cli_callback)
req->tw_cli_callback(req);
}
}
/*
* Function name: tw_cli_complete_io
* Description: CL internal callback for SCSI/fw passthru requests.
*
* Input: req -- ptr to CL internal request context
* Output: None
* Return value: None
*/
TW_VOID
tw_cli_complete_io(struct tw_cli_req_context *req)
{
struct tw_cli_ctlr_context *ctlr = req->ctlr;
struct tw_cl_req_packet *req_pkt =
(struct tw_cl_req_packet *)(req->orig_req);
tw_cli_dbg_printf(8, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
req_pkt->status = TW_CL_ERR_REQ_SUCCESS;
if (req->error_code) {
req_pkt->status = TW_CL_ERR_REQ_UNABLE_TO_SUBMIT_COMMAND;
goto out;
}
if (req->state != TW_CLI_REQ_STATE_COMPLETE) {
tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1203, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"I/O completion on incomplete command!!",
"request = %p, status = %d",
req, req->state);
#ifdef TW_OSL_DEBUG
tw_cl_print_ctlr_stats(ctlr->ctlr_handle);
#endif /* TW_OSL_DEBUG */
tw_cl_reset_ctlr(ctlr->ctlr_handle);
req_pkt->status = TW_CL_ERR_REQ_BUS_RESET;
goto out;
}
if (req->flags & TW_CLI_REQ_FLAGS_PASSTHRU) {
/* Copy the command packet back into OSL's space. */
tw_osl_memcpy(req_pkt->gen_req_pkt.pt_req.cmd_pkt, req->cmd_pkt,
sizeof(struct tw_cl_command_packet));
} else
tw_cli_scsi_complete(req);
out:
req_pkt->tw_osl_callback(req->req_handle);
tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
}
/*
* Function name: tw_cli_scsi_complete
* Description: Completion routine for SCSI requests.
*
* Input: req -- ptr to CL internal request context
* Output: None
* Return value: None
*/
TW_VOID
tw_cli_scsi_complete(struct tw_cli_req_context *req)
{
struct tw_cl_req_packet *req_pkt =
(struct tw_cl_req_packet *)(req->orig_req);
struct tw_cl_scsi_req_packet *scsi_req =
&(req_pkt->gen_req_pkt.scsi_req);
struct tw_cl_command_9k *cmd =
&(req->cmd_pkt->command.cmd_pkt_9k);
struct tw_cl_command_header *cmd_hdr;
TW_UINT16 error;
TW_UINT8 *cdb;
tw_cli_dbg_printf(8, req->ctlr->ctlr_handle, tw_osl_cur_func(),
"entered");
scsi_req->scsi_status = cmd->status;
if (! cmd->status)
return;
tw_cli_dbg_printf(1, req->ctlr->ctlr_handle, tw_osl_cur_func(),
"req_id = 0x%x, status = 0x%x",
GET_REQ_ID(cmd->lun_l4__req_id), cmd->status);
cmd_hdr = &(req->cmd_pkt->cmd_hdr);
error = cmd_hdr->status_block.error;
if ((error == TWA_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) ||
(error == TWA_ERROR_UNIT_OFFLINE)) {
if (GET_LUN_L4(cmd->lun_l4__req_id))
req_pkt->status |= TW_CL_ERR_REQ_INVALID_LUN;
else
req_pkt->status |= TW_CL_ERR_REQ_INVALID_TARGET;
} else {
tw_cli_dbg_printf(2, req->ctlr->ctlr_handle,
tw_osl_cur_func(),
"cmd = %x %x %x %x %x %x %x",
GET_OPCODE(cmd->res__opcode),
GET_SGL_OFF(cmd->res__opcode),
cmd->unit,
cmd->lun_l4__req_id,
cmd->status,
cmd->sgl_offset,
cmd->lun_h4__sgl_entries);
cdb = (TW_UINT8 *)(cmd->cdb);
tw_cli_dbg_printf(2, req->ctlr->ctlr_handle,
tw_osl_cur_func(),
"cdb = %x %x %x %x %x %x %x %x "
"%x %x %x %x %x %x %x %x",
cdb[0], cdb[1], cdb[2], cdb[3],
cdb[4], cdb[5], cdb[6], cdb[7],
cdb[8], cdb[9], cdb[10], cdb[11],
cdb[12], cdb[13], cdb[14], cdb[15]);
/*
* Print the error. Firmware doesn't yet support
* the 'Mode Sense' cmd. Don't print if the cmd
* is 'Mode Sense', and the error is 'Invalid field
* in CDB'.
*/
if (! ((cdb[0] == 0x1A) && (error == 0x10D)))
tw_cli_create_ctlr_event(req->ctlr,
TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR,
cmd_hdr);
}
if (scsi_req->sense_data) {
tw_osl_memcpy(scsi_req->sense_data, cmd_hdr->sense_data,
TWA_SENSE_DATA_LENGTH);
scsi_req->sense_len = TWA_SENSE_DATA_LENGTH;
req_pkt->status |= TW_CL_ERR_REQ_AUTO_SENSE_VALID;
}
req_pkt->status |= TW_CL_ERR_REQ_SCSI_ERROR;
}
/*
* Function name: tw_cli_param_callback
* Description: Callback for get/set_param requests.
*
* Input: req -- ptr to completed request pkt
* Output: None
* Return value: None
*/
TW_VOID
tw_cli_param_callback(struct tw_cli_req_context *req)
{
struct tw_cli_ctlr_context *ctlr = req->ctlr;
union tw_cl_command_7k *cmd =
&(req->cmd_pkt->command.cmd_pkt_7k);
TW_INT32 error;
tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
/*
* If the request was never submitted to the controller, the function
* that sets req->error is responsible for calling tw_cl_create_event.
*/
if (! req->error_code)
if (cmd->param.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,
0x1204, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"get/set_param failed",
"status = %d", cmd->param.status);
}
ctlr->state &= ~TW_CLI_CTLR_STATE_INTERNAL_REQ_BUSY;
tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
if ((ctlr->state & TW_CLI_CTLR_STATE_GET_MORE_AENS) &&
(!(ctlr->state & TW_CLI_CTLR_STATE_RESET_IN_PROGRESS))) {
ctlr->state &= ~TW_CLI_CTLR_STATE_GET_MORE_AENS;
tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
"Fetching more AEN's");
if ((error = tw_cli_get_aen(ctlr)))
tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1205, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"Failed to fetch all AEN's from param_callback",
"error = %d", error);
}
}
/*
* Function name: tw_cli_aen_callback
* Description: Callback for requests to fetch AEN's.
*
* Input: req -- ptr to completed request pkt
* Output: None
* Return value: None
*/
TW_VOID
tw_cli_aen_callback(struct tw_cli_req_context *req)
{
struct tw_cli_ctlr_context *ctlr = req->ctlr;
struct tw_cl_command_header *cmd_hdr;
struct tw_cl_command_9k *cmd =
&(req->cmd_pkt->command.cmd_pkt_9k);
TW_UINT16 aen_code = TWA_AEN_QUEUE_EMPTY;
TW_INT32 error;
tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
"req_id = 0x%x, req error = %d, status = 0x%x",
GET_REQ_ID(cmd->lun_l4__req_id), req->error_code, cmd->status);
/*
* If the request was never submitted to the controller, the function
* that sets error is responsible for calling tw_cl_create_event.
*/
if (!(error = req->error_code))
if ((error = cmd->status)) {
cmd_hdr = (struct tw_cl_command_header *)
(&(req->cmd_pkt->cmd_hdr));
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,
0x1206, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"Request Sense failed",
"opcode = 0x%x, status = %d",
GET_OPCODE(cmd->res__opcode), cmd->status);
}
if (error) {
ctlr->state &= ~TW_CLI_CTLR_STATE_INTERNAL_REQ_BUSY;
tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
return;
}
tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
"Request Sense command succeeded");
aen_code = tw_cli_manage_aen(ctlr, req);
if (aen_code != TWA_AEN_SYNC_TIME_WITH_HOST) {
ctlr->state &= ~TW_CLI_CTLR_STATE_INTERNAL_REQ_BUSY;
tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
if (aen_code != TWA_AEN_QUEUE_EMPTY)
if ((error = tw_cli_get_aen(ctlr)))
tw_cl_create_event(ctlr->ctlr_handle,
TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1207, 0x1,
TW_CL_SEVERITY_ERROR_STRING,
"Failed to fetch all AEN's",
"error = %d", error);
}
}
/*
* Function name: tw_cli_manage_aen
* Description: Handles AEN's.
*
* Input: ctlr -- ptr to CL internal ctlr context
* req -- ptr to CL internal request context
* Output: None
* Return value: None
*/
TW_UINT16
tw_cli_manage_aen(struct tw_cli_ctlr_context *ctlr,
struct tw_cli_req_context *req)
{
struct tw_cl_command_header *cmd_hdr;
TW_UINT16 aen_code;
TW_TIME local_time;
TW_TIME sync_time;
TW_UINT32 error;
tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
cmd_hdr = (struct tw_cl_command_header *)(req->data);
aen_code = cmd_hdr->status_block.error;
switch (aen_code) {
case TWA_AEN_SYNC_TIME_WITH_HOST:
tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
"Received AEN_SYNC_TIME");
/*
* Free the internal req pkt right here, since
* tw_cli_set_param will need it.
*/
ctlr->state &= ~TW_CLI_CTLR_STATE_INTERNAL_REQ_BUSY;
tw_cli_req_q_insert_tail(req, TW_CLI_FREE_Q);
/*
* We will use a callback in tw_cli_set_param only when
* interrupts are enabled and we can expect our callback
* to get called. Setting the TW_CLI_CTLR_STATE_GET_MORE_AENS
* flag will make the callback continue to try to retrieve
* more AEN's.
*/
if (ctlr->state & TW_CLI_CTLR_STATE_INTR_ENABLED)
ctlr->state |= TW_CLI_CTLR_STATE_GET_MORE_AENS;
/* Calculate time (in seconds) since last Sunday 12.00 AM. */
local_time = tw_osl_get_local_time();
sync_time = (local_time - (3 * 86400)) % 604800;
if ((error = tw_cli_set_param(ctlr, TWA_PARAM_TIME_TABLE,
TWA_PARAM_TIME_SCHED_TIME, 4,
&sync_time,
(ctlr->state & TW_CLI_CTLR_STATE_INTR_ENABLED)
? tw_cli_param_callback : TW_CL_NULL)))
tw_cl_create_event(ctlr->ctlr_handle, TW_CL_FALSE,
TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR,
0x1208, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"Unable to sync time with ctlr",
"error = %d", error);
break;
case TWA_AEN_QUEUE_EMPTY:
tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
"AEN queue empty");
break;
default:
/* Queue the event. */
tw_cli_dbg_printf(4, ctlr->ctlr_handle, tw_osl_cur_func(),
"Queueing AEN");
tw_cli_create_ctlr_event(ctlr,
TW_CL_MESSAGE_SOURCE_CONTROLLER_EVENT,
cmd_hdr);
break;
} /* switch */
return(aen_code);
}
/*
* Function name: tw_cli_enable_interrupts
* Description: Enables interrupts on the controller
*
* Input: ctlr -- ptr to CL internal ctlr context
* Output: None
* Return value: None
*/
TW_VOID
tw_cli_enable_interrupts(struct tw_cli_ctlr_context *ctlr)
{
tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
ctlr->state |= TW_CLI_CTLR_STATE_INTR_ENABLED;
TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle,
TWA_CONTROL_CLEAR_ATTENTION_INTERRUPT |
TWA_CONTROL_UNMASK_RESPONSE_INTERRUPT |
TWA_CONTROL_ENABLE_INTERRUPTS);
}
/*
* Function name: twa_setup
* Description: Disables interrupts on the controller
*
* Input: ctlr -- ptr to CL internal ctlr context
* Output: None
* Return value: None
*/
TW_VOID
tw_cli_disable_interrupts(struct tw_cli_ctlr_context *ctlr)
{
tw_cli_dbg_printf(3, ctlr->ctlr_handle, tw_osl_cur_func(), "entered");
TW_CLI_WRITE_CONTROL_REGISTER(ctlr->ctlr_handle,
TWA_CONTROL_DISABLE_INTERRUPTS);
ctlr->state &= ~TW_CLI_CTLR_STATE_INTR_ENABLED;
}

1414
sys/dev/twa/tw_cl_io.c Normal file

File diff suppressed because it is too large Load Diff

102
sys/dev/twa/tw_cl_ioctl.h Normal file
View File

@ -0,0 +1,102 @@
/*
* 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
*/
#ifndef TW_CL_IOCTL_H
#define TW_CL_IOCTL_H
/*
* Macros and structures for Common Layer handled ioctls.
*/
#define TW_CL_AEN_NOT_RETRIEVED 0x1
#define TW_CL_AEN_RETRIEVED 0x2
#define TW_CL_ERROR_AEN_NO_EVENTS 0x1003 /* No more events */
#define TW_CL_ERROR_AEN_OVERFLOW 0x1004 /* AEN overflow occurred */
#define TW_CL_ERROR_IOCTL_LOCK_NOT_HELD 0x1001 /* Not locked */
#define TW_CL_ERROR_IOCTL_LOCK_ALREADY_HELD 0x1002 /* Already locked */
#pragma pack(1)
/* Structure used to handle GET/RELEASE LOCK ioctls. */
struct tw_cl_lock_packet {
TW_UINT32 timeout_msec;
TW_UINT32 time_remaining_msec;
TW_UINT32 force_flag;
};
/* Structure used to handle GET COMPATIBILITY INFO ioctl. */
struct tw_cl_compatibility_packet {
TW_UINT8 driver_version[32];/* driver version */
TW_UINT16 working_srl; /* driver & firmware negotiated srl */
TW_UINT16 working_branch; /* branch # of the firmware that the
driver is compatible with */
TW_UINT16 working_build; /* build # of the firmware that the
driver is compatible with */
};
/* Driver understandable part of the ioctl packet built by the API. */
struct tw_cl_driver_packet {
TW_UINT32 control_code;
TW_UINT32 status;
TW_UINT32 unique_id;
TW_UINT32 sequence_id;
TW_UINT32 os_status;
TW_UINT32 buffer_length;
};
/* ioctl packet built by the API. */
struct tw_cl_ioctl_packet {
struct tw_cl_driver_packet driver_pkt;
TW_INT8 padding[488];
struct tw_cl_command_packet cmd_pkt;
TW_INT8 data_buf[1];
};
#pragma pack()
#endif /* TW_CL_IOCTL_H */

1053
sys/dev/twa/tw_cl_misc.c Normal file

File diff suppressed because it is too large Load Diff

591
sys/dev/twa/tw_cl_share.h Normal file
View File

@ -0,0 +1,591 @@
/*
* 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
*/
#ifndef TW_CL_SHARE_H
#define TW_CL_SHARE_H
/*
* Macros, structures and functions shared between OSL and CL,
* and defined by CL.
*/
#define TW_CL_VERSION_STRING "1.00.00.007"
#define TW_CL_NULL ((TW_VOID *)0)
#define TW_CL_TRUE 1
#define TW_CL_FALSE 0
#define TW_CL_VENDOR_ID 0x13C1 /* 3ware vendor id */
#define TW_CL_DEVICE_ID_9K 0x1002 /* 9000 series device id */
#define TW_CL_MAX_NUM_UNITS 16 /* max # of units we support */
#define TW_CL_MAX_NUM_LUNS 16 /* max # of LUN's we support */
#define TW_CL_MAX_IO_SIZE 0x20000 /* 128K */
/*
* Though we can support 256 simultaneous requests, we advertise as capable
* of supporting only 255, since we want to keep one CL internal request
* context packet always available for internal requests.
*/
#define TW_CL_MAX_SIMULTANEOUS_REQUESTS 0xFF /* max simult reqs supported */
#define TW_CL_MAX_32BIT_SG_ELEMENTS 109 /* max 32-bit sg elements */
#define TW_CL_MAX_64BIT_SG_ELEMENTS 72 /* max 64-bit sg elements */
/* Possible values of ctlr->flags */
#define TW_CL_64BIT_ADDRESSES (1<<0) /* 64 bit cmdpkt & SG addresses */
#define TW_CL_64BIT_SG_LENGTH (1<<1) /* 64 bit SG length */
#define TW_CL_START_CTLR_ONLY (1<<2) /* Start ctlr only */
#define TW_CL_STOP_CTLR_ONLY (1<<3) /* Stop ctlr only */
#define TW_CL_FLASH_FIRMWARE (1<<4) /* Flash firmware */
/* Possible error values from the Common Layer. */
#define TW_CL_ERR_REQ_SUCCESS 0
#define TW_CL_ERR_REQ_GENERAL_FAILURE (1<<0)
#define TW_CL_ERR_REQ_INVALID_TARGET (1<<1)
#define TW_CL_ERR_REQ_INVALID_LUN (1<<2)
#define TW_CL_ERR_REQ_SCSI_ERROR (1<<3)
#define TW_CL_ERR_REQ_AUTO_SENSE_VALID (1<<4)
#define TW_CL_ERR_REQ_BUS_RESET (1<<5)
#define TW_CL_ERR_REQ_UNABLE_TO_SUBMIT_COMMAND (1<<6)
/* Possible values of req_pkt->flags */
#ifndef TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST
#define TW_CL_REQ_RETRY_ON_BUSY (1<<0)
#endif /* TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST */
#define TW_CL_REQ_CALLBACK_FOR_SGLIST (1<<1)
#define TW_CL_MESSAGE_SOURCE_CONTROLLER_ERROR 3
#define TW_CL_MESSAGE_SOURCE_CONTROLLER_EVENT 4
#define TW_CL_MESSAGE_SOURCE_COMMON_LAYER_ERROR 21
#define TW_CL_MESSAGE_SOURCE_COMMON_LAYER_EVENT 22
#define TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER 5
#define TW_CL_MESSAGE_SOURCE_FREEBSD_OS 8
#define TW_CL_MESSAGE_SOURCE_WINDOWS_DRIVER 7
#define TW_CL_MESSAGE_SOURCE_WINDOWS_OS 10
#define TW_CL_SEVERITY_ERROR 0x1
#define TW_CL_SEVERITY_WARNING 0x2
#define TW_CL_SEVERITY_INFO 0x3
#define TW_CL_SEVERITY_DEBUG 0x4
#define TW_CL_SEVERITY_ERROR_STRING "ERROR"
#define TW_CL_SEVERITY_WARNING_STRING "WARNING"
#define TW_CL_SEVERITY_INFO_STRING "INFO"
#define TW_CL_SEVERITY_DEBUG_STRING "DEBUG"
#pragma pack(1)
/*
* Structure, a pointer to which is used as the controller handle in
* communications between the OS Layer and the Common Layer.
*/
struct tw_cl_ctlr_handle {
TW_VOID *osl_ctlr_ctxt; /* OSL's ctlr context */
TW_VOID *cl_ctlr_ctxt; /* CL's ctlr context */
};
/*
* Structure, a pointer to which is used as the request handle in
* communications between the OS Layer and the Common Layer.
*/
struct tw_cl_req_handle {
TW_VOID *osl_req_ctxt; /* OSL's request context */
TW_VOID *cl_req_ctxt; /* CL's request context */
};
/* Structure used to describe SCSI requests to CL. */
struct tw_cl_scsi_req_packet {
TW_UINT32 unit; /* unit # to send cmd to */
TW_UINT32 lun; /* LUN to send cmd to */
TW_UINT8 *cdb; /* ptr to SCSI cdb */
TW_UINT32 cdb_len; /* # of valid cdb bytes */
TW_UINT32 sense_len; /* # of bytes of valid sense info */
TW_UINT8 *sense_data; /* ptr to sense data, if any */
TW_UINT32 scsi_status; /* SCSI status returned by fw */
TW_UINT32 sgl_entries; /* # of SG descriptors */
TW_UINT8 *sg_list; /* ptr to SG list */
};
/* Structure used to describe pass through command packets to CL. */
struct tw_cl_passthru_req_packet {
TW_UINT8 *cmd_pkt; /* ptr to passthru cmd pkt */
TW_UINT32 cmd_pkt_length; /* size of cmd pkt */
TW_UINT32 sgl_entries; /* # of SG descriptors */
TW_UINT8 *sg_list; /* ptr to SG list */
};
/* Request packet submitted to the Common Layer, by the OS Layer. */
struct tw_cl_req_packet {
TW_UINT32 cmd; /* Common Layer cmd */
TW_UINT32 flags; /* flags describing request */
TW_UINT32 status; /* Common Layer returned status */
TW_VOID (*tw_osl_callback)(struct tw_cl_req_handle *req_handle);
/* OSL routine to be called by CL on req completion */
TW_VOID (*tw_osl_sgl_callback)(
struct tw_cl_req_handle *req_handle, TW_VOID *sg_list,
TW_UINT32 *num_sgl_entries);
/* OSL callback to get SG list. */
#ifdef TW_OSL_DMA_MEM_ALLOC_PER_REQUEST
TW_VOID *dma_mem;
TW_UINT64 dma_mem_phys;
#endif /* TW_OSL_DMA_MEM_ALLOC_PER_REQUEST */
#ifdef TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST
TW_VOID *non_dma_mem;
#endif /* TW_OSL_NON_DMA_MEM_ALLOC_PER_REQUEST */
union {
struct tw_cl_scsi_req_packet scsi_req; /* SCSI req */
struct tw_cl_passthru_req_packet pt_req;/*Passthru req*/
} gen_req_pkt;
};
/*
* Packet that describes an AEN/error generated by the controller,
* Common Layer, or even the OS Layer.
*/
struct tw_cl_event_packet {
TW_UINT32 sequence_id;
TW_UINT32 time_stamp_sec;
TW_UINT16 aen_code;
TW_UINT8 severity;
TW_UINT8 retrieved;
TW_UINT8 repeat_count;
TW_UINT8 parameter_len;
TW_UINT8 parameter_data[98];
TW_UINT32 event_src;
TW_UINT8 severity_str[20];
};
/* Structure to link 2 adjacent elements in a list. */
struct tw_cl_link {
struct tw_cl_link *next;
struct tw_cl_link *prev;
};
/* Scatter/Gather list entry with 32 bit addresses. */
struct tw_cl_sg_desc32 {
TW_UINT32 address;
TW_UINT32 length;
};
/* Scatter/Gather list entry with 64 bit addresses. */
struct tw_cl_sg_desc64 {
TW_UINT64 address;
TW_UINT32 length;
};
#pragma pack()
/* Byte swap functions. Valid only if running on big endian platforms. */
#ifdef TW_OSL_BIG_ENDIAN
#define TW_CL_SWAP16_WITH_CAST(x) \
((x << 8) | (x >> 8))
#define TW_CL_SWAP32_WITH_CAST(x) \
((x << 24) | ((x << 8) & (0xFF0000)) | \
((x >> 8) & (0xFF00)) | (x >> 24))
#define TW_CL_SWAP64_WITH_CAST(x) \
((((TW_UINT64)(TW_CL_SWAP32(((TW_UINT32 *)(&(x)))[1]))) << 32) |\
((TW_UINT32)(TW_CL_SWAP32(((TW_UINT32 *)(&(x)))[0]))))
#else /* TW_OSL_BIG_ENDIAN */
#define TW_CL_SWAP16_WITH_CAST(x) x
#define TW_CL_SWAP32_WITH_CAST(x) x
#define TW_CL_SWAP64_WITH_CAST(x) x
#endif /* TW_OSL_BIG_ENDIAN */
#define TW_CL_SWAP16(x) TW_CL_SWAP16_WITH_CAST((TW_UINT16)(x))
#define TW_CL_SWAP32(x) TW_CL_SWAP32_WITH_CAST((TW_UINT32)(x))
#define TW_CL_SWAP64(x) TW_CL_SWAP64_WITH_CAST((TW_UINT64)(x))
/* Queue manipulation functions. */
/* Initialize a queue. */
#define TW_CL_Q_INIT(head) do { \
(head)->prev = (head)->next = head; \
} while (0)
/* Insert an item at the head of the queue. */
#define TW_CL_Q_INSERT_HEAD(head, item) do { \
(item)->next = (head)->next; \
(item)->prev = head; \
(head)->next->prev = item; \
(head)->next = item; \
} while (0)
/* Insert an item at the tail of the queue. */
#define TW_CL_Q_INSERT_TAIL(head, item) do { \
(item)->next = head; \
(item)->prev = (head)->prev; \
(head)->prev->next = item; \
(head)->prev = item; \
} while (0)
/* Remove an item from the head of the queue. */
#define TW_CL_Q_REMOVE_ITEM(head, item) do { \
(item)->prev->next = (item)->next; \
(item)->next->prev = (item)->prev; \
} while (0)
/* Retrieve the item at the head of the queue. */
#define TW_CL_Q_FIRST_ITEM(head) \
(((head)->next != head) ? ((head)->next) : TW_CL_NULL)
/* Retrieve the item at the tail of the queue. */
#define TW_CL_Q_LAST_ITEM(head) \
(((head)->prev != head) ? ((head)->prev) : TW_CL_NULL)
/* Retrieve the item next to a given item in the queue. */
#define TW_CL_Q_NEXT_ITEM(head, item) \
(((item)->next != head) ? ((item)->next) : TW_CL_NULL)
/* Retrieve the item previous to a given item in the queue. */
#define TW_CL_Q_PREV_ITEM(head, item) \
(((item)->prev != head) ? ((item)->prev) : TW_CL_NULL)
/* Determine the offset of a field from the head of the structure it is in. */
#define TW_CL_STRUCT_OFFSET(struct_type, field) \
(TW_INT8 *)(&((struct_type *)0)->field)
/*
* Determine the address of the head of a structure, given the address of a
* field within it.
*/
#define TW_CL_STRUCT_HEAD(addr, struct_type, field) \
(struct_type *)((TW_INT8 *)addr - \
TW_CL_STRUCT_OFFSET(struct_type, field))
/*
* The following are extern declarations of OS Layer defined functions called
* by the Common Layer. If any function has been defined as a macro in
* tw_osl_share.h, we will not make the extern declaration here.
*/
#ifndef tw_osl_breakpoint
/* Allows setting breakpoints in the CL code for debugging purposes. */
extern TW_VOID tw_osl_breakpoint(TW_VOID);
#endif
#ifndef tw_osl_ctlr_ready
/* Called on cmd interrupt. Allows re-submission of any pending requests. */
extern TW_VOID tw_osl_ctlr_ready(struct tw_cl_ctlr_handle *ctlr_handle);
#endif
#ifndef tw_osl_cur_func
/* Text name of current function. */
extern TW_INT8 *tw_osl_cur_func(TW_VOID);
#endif
#ifdef TW_OSL_DEBUG
#ifndef tw_osl_dbg_printf
/* Print to syslog/event log/debug console, as applicable. */
extern TW_INT32 tw_osl_dbg_printf(struct tw_cl_ctlr_handle *ctlr_handle,
const TW_INT8 *fmt, ...);
#endif
#endif /* TW_OSL_DEBUG */
#ifndef tw_osl_delay
/* Cause a delay of usecs micro-seconds. */
extern TW_VOID tw_osl_delay(TW_INT32 usecs);
#endif
#ifndef tw_osl_destroy_lock
/* Create/initialize a lock for CL's use. */
extern TW_VOID tw_osl_destroy_lock(struct tw_cl_ctlr_handle *ctlr_handle,
TW_LOCK_HANDLE *lock);
#endif
#ifndef tw_osl_free_lock
/* Free a previously held lock. */
extern TW_VOID tw_osl_free_lock(struct tw_cl_ctlr_handle *ctlr_handle,
TW_LOCK_HANDLE *lock);
#endif
#ifndef tw_osl_get_local_time
/* Get local time. */
extern TW_TIME tw_osl_get_local_time(TW_VOID);
#endif
#ifndef tw_osl_get_lock
/* Acquire a lock. */
extern TW_VOID tw_osl_get_lock(struct tw_cl_ctlr_handle *ctlr_handle,
TW_LOCK_HANDLE *lock);
#endif
#ifndef tw_osl_init_lock
/* Create/initialize a lock for CL's use. */
extern TW_VOID tw_osl_init_lock(struct tw_cl_ctlr_handle *ctlr_handle,
TW_INT8 *lock_name, TW_LOCK_HANDLE *lock);
#endif
#ifndef tw_osl_memcpy
/* Copy 'size' bytes from 'src' to 'dest'. */
extern TW_VOID tw_osl_memcpy(TW_VOID *src, TW_VOID *dest, TW_INT32 size);
#endif
#ifndef tw_osl_memzero
/* Zero 'size' bytes starting at 'addr'. */
extern TW_VOID tw_osl_memzero(TW_VOID *addr, TW_INT32 size);
#endif
#ifndef tw_osl_notify_event
/* Notify OSL of a controller/CL (or even OSL) event. */
extern TW_VOID tw_osl_notify_event(struct tw_cl_ctlr_handle *ctlr_handle,
struct tw_cl_event_packet *event);
#endif
#ifdef TW_OSL_PCI_CONFIG_ACCESSIBLE
#ifndef tw_osl_read_pci_config
/* Read 'size' bytes from 'offset' in the PCI config space. */
extern TW_UINT32 tw_osl_read_pci_config(
struct tw_cl_ctlr_handle *ctlr_handle, TW_INT32 offset, TW_INT32 size);
#endif
#endif /* TW_OSL_PCI_CONFIG_ACCESSIBLE */
#ifndef tw_osl_read_reg
/* Read 'size' bytes at 'offset' from base address of this controller. */
extern TW_UINT32 tw_osl_read_reg(struct tw_cl_ctlr_handle *ctlr_handle,
TW_INT32 offset, TW_INT32 size);
#endif
#ifndef tw_osl_scan_bus
/* Request OSL for a bus scan. */
extern TW_VOID tw_osl_scan_bus(struct tw_cl_ctlr_handle *ctlr_handle);
#endif
#ifdef TW_OSL_CAN_SLEEP
#ifndef tw_osl_sleep
/* Sleep for 'timeout' ms or until woken up (by tw_osl_wakeup). */
extern TW_INT32 tw_osl_sleep(struct tw_cl_ctlr_handle *ctlr_handle,
TW_SLEEP_HANDLE *sleep_handle, TW_INT32 timeout);
#endif
#endif /* TW_OSL_CAN_SLEEP */
#ifndef tw_osl_sprintf
/* Standard sprintf. */
extern TW_INT32 tw_osl_sprintf(TW_INT8 *dest, const TW_INT8 *fmt, ...);
#endif
#ifndef tw_osl_strcpy
/* Copy string 'src' to 'dest'. */
extern TW_INT8 *tw_osl_strcpy(TW_INT8 *dest, TW_INT8 *src);
#endif
#ifndef tw_osl_strlen
/* Return length of string pointed at by 'str'. */
extern TW_INT32 tw_osl_strlen(TW_VOID *str);
#endif
#ifdef TW_OSL_CAN_SLEEP
#ifndef tw_osl_wakeup
/* Wake up a thread sleeping by a call to tw_osl_sleep. */
extern TW_VOID tw_osl_wakeup(struct tw_cl_ctlr_handle *ctlr_handle,
TW_SLEEP_HANDLE *sleep_handle);
#endif
#endif /* TW_OSL_CAN_SLEEP */
#ifdef TW_OSL_PCI_CONFIG_ACCESSIBLE
#ifndef tw_osl_write_pci_config
/* Write 'value' of 'size' bytes at 'offset' in the PCI config space. */
extern TW_VOID tw_osl_write_pci_config(struct tw_cl_ctlr_handle *ctlr_handle,
TW_INT32 offset, TW_INT32 value, TW_INT32 size);
#endif
#endif /* TW_OSL_PCI_CONFIG_ACCESSIBLE */
#ifndef tw_osl_write_reg
/*
* Write 'value' of 'size' (max 4) bytes at 'offset' from base address of
* this controller.
*/
extern TW_VOID tw_osl_write_reg(struct tw_cl_ctlr_handle *ctlr_handle,
TW_INT32 offset, TW_INT32 value, TW_INT32 size);
#endif
/* Functions in the Common Layer */
/* Creates and queues AEN's. Also notifies OS Layer. */
extern TW_VOID tw_cl_create_event(struct tw_cl_ctlr_handle *ctlr_handle,
TW_UINT8 queue_event, TW_UINT8 event_src, TW_UINT16 event_code,
TW_UINT8 severity, TW_UINT8 *severity_str, TW_UINT8 *event_desc,
TW_UINT8 *event_specific_desc, ...);
/* Indicates whether a ctlr is supported by CL. */
extern TW_INT32 tw_cl_ctlr_supported(TW_INT32 vendor_id, TW_INT32 device_id);
/* Deferred interrupt handler. */
extern TW_VOID tw_cl_deferred_interrupt(struct tw_cl_ctlr_handle *ctlr_handle);
/* Submit a firmware cmd packet. */
extern TW_INT32 tw_cl_fw_passthru(struct tw_cl_ctlr_handle *ctlr_handle,
struct tw_cl_req_packet *req_pkt, struct tw_cl_req_handle *req_handle);
/* Find out how much memory CL needs. */
extern TW_INT32 tw_cl_get_mem_requirements(
struct tw_cl_ctlr_handle *ctlr_handle, TW_UINT32 flags,
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 */
);
/* Initialize Common Layer for a given controller. */
extern TW_INT32 tw_cl_init_ctlr(struct tw_cl_ctlr_handle *ctlr_handle,
TW_UINT32 flags, 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 */
);
/* CL's interrupt handler. */
extern TW_INT32 tw_cl_interrupt(struct tw_cl_ctlr_handle *ctlr_handle);
/* CL's ioctl handler. */
extern TW_INT32 tw_cl_ioctl(struct tw_cl_ctlr_handle *ctlr_handle,
TW_INT32 cmd, TW_VOID *buf);
#ifdef TW_OSL_DEBUG
/* Print CL's state/statistics for a controller. */
extern TW_VOID tw_cl_print_ctlr_stats(struct tw_cl_ctlr_handle *ctlr_handle);
/* Prints CL internal details of a given request. */
extern TW_VOID tw_cl_print_req_info(struct tw_cl_req_handle *req_handle);
#endif /* TW_OSL_DEBUG */
/* Soft reset controller. */
extern TW_INT32 tw_cl_reset_ctlr(struct tw_cl_ctlr_handle *ctlr_handle);
#ifdef TW_OSL_DEBUG
/* Reset CL's statistics for a controller. */
extern TW_VOID tw_cl_reset_stats(struct tw_cl_ctlr_handle *ctlr_handle);
#endif /* TW_OSL_DEBUG */
/* Stop a controller. */
extern TW_INT32 tw_cl_shutdown_ctlr(struct tw_cl_ctlr_handle *ctlr_handle,
TW_UINT32 flags);
/* Submit a SCSI I/O request. */
extern TW_INT32 tw_cl_start_io(struct tw_cl_ctlr_handle *ctlr_handle,
struct tw_cl_req_packet *req_pkt, struct tw_cl_req_handle *req_handle);
#endif /* TW_CL_SHARE_H */

316
sys/dev/twa/tw_osl.h Normal file
View File

@ -0,0 +1,316 @@
/*
* 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
*/
#ifndef TW_OSL_H
#define TW_OSL_H
/*
* OS Layer internal macros, structures and functions.
*/
#define TW_OSLI_DEVICE_NAME "3ware 9000 series Storage Controller"
#define TW_OSLI_MALLOC_CLASS M_TWA
#define TW_OSLI_MAX_NUM_IOS TW_CL_MAX_SIMULTANEOUS_REQUESTS
#define TW_OSLI_MAX_NUM_AENS 0x100
/* Possible values of req->state. */
#define TW_OSLI_REQ_STATE_INIT 0x0 /* being initialized */
#define TW_OSLI_REQ_STATE_BUSY 0x1 /* submitted to CL */
#define TW_OSLI_REQ_STATE_PENDING 0x2 /* in pending queue */
#define TW_OSLI_REQ_STATE_COMPLETE 0x3 /* completed by CL */
/* Possible values of req->flags. */
#define TW_OSLI_REQ_FLAGS_DATA_IN (1<<0) /* read request */
#define TW_OSLI_REQ_FLAGS_DATA_OUT (1<<1) /* write request */
#define TW_OSLI_REQ_FLAGS_DATA_COPY_NEEDED (1<<2)/* data in ccb is misaligned,
have to copy to/from private buffer */
#define TW_OSLI_REQ_FLAGS_MAPPED (1<<3) /* request has been mapped */
#define TW_OSLI_REQ_FLAGS_IN_PROGRESS (1<<4) /* bus_dmamap_load returned
EINPROGRESS */
#define TW_OSLI_REQ_FLAGS_PASSTHRU (1<<5) /* pass through request */
#define TW_OSLI_REQ_FLAGS_SLEEPING (1<<6) /* owner sleeping on this cmd */
/* Possible values of sc->state. */
#define TW_OSLI_CTLR_STATE_OPEN (1<<0) /* control device is open */
#define TW_OSLI_CTLR_STATE_SIMQ_FROZEN (1<<1) /* simq frozen */
#ifdef TW_OSL_DEBUG
struct tw_osli_q_stats {
TW_UINT32 cur_len; /* current # of items in q */
TW_UINT32 max_len; /* max value reached by q_length */
};
#endif /* TW_OSL_DEBUG */
/* Queues of OSL internal request context packets. */
#define TW_OSLI_FREE_Q 0 /* free q */
#define TW_OSLI_BUSY_Q 1 /* q of reqs submitted to CL */
#define TW_OSLI_Q_COUNT 2 /* total number of queues */
/* Driver's request packet. */
struct tw_osli_req_context {
struct tw_cl_req_handle req_handle;/* tag to track req b/w OSL & CL */
struct twa_softc *ctlr; /* ptr to OSL's controller context */
TW_VOID *data; /* ptr to data being passed to CL */
TW_UINT32 length; /* length of buf being passed to CL */
/*
* ptr to, and length of data passed to us from above, in case a buffer
* copy was done due to non-compliance to alignment requirements
*/
TW_VOID *real_data;
TW_UINT32 real_length;
TW_UINT32 state; /* request state */
TW_UINT32 flags; /* request flags */
/* error encountered before request submission to CL */
TW_UINT32 error_code;
/* ptr to orig req for use during callback */
TW_VOID *orig_req;
struct tw_cl_link link; /* to link this request in a list */
bus_dmamap_t dma_map;/* DMA map for data */
struct tw_cl_req_packet req_pkt;/* req pkt understood by CL */
};
/* Per-controller structure. */
struct twa_softc {
struct tw_cl_ctlr_handle ctlr_handle;
struct tw_osli_req_context *req_ctxt_buf;
/* Controller state. */
TW_UINT32 state;
TW_UINT32 flags;
TW_UINT32 alignment;
TW_UINT32 sg_size_factor;
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 */
/* Request queues and arrays. */
struct tw_cl_link req_q_head[TW_OSLI_Q_COUNT];
struct task deferred_intr_callback;/* taskqueue function */
struct mtx io_lock_handle;/* general purpose lock */
struct mtx *io_lock;/* ptr to general purpose lock */
struct mtx q_lock_handle; /* queue manipulation lock */
struct mtx *q_lock;/* ptr to queue manipulation lock */
#ifdef TW_OSL_DEBUG
struct tw_osli_q_stats q_stats[TW_OSLI_Q_COUNT];/* queue statistics */
#endif /* TW_OSL_DEBUG */
device_t bus_dev; /* bus device */
struct cdev *ctrl_dev; /* control device */
struct resource *reg_res; /* register interface window */
TW_INT32 reg_res_id; /* register resource id */
bus_space_handle_t bus_handle; /* bus space handle */
bus_space_tag_t bus_tag; /* bus space tag */
bus_dma_tag_t parent_tag; /* parent DMA tag */
bus_dma_tag_t cmd_tag; /* DMA tag for CL's DMA'able mem */
bus_dma_tag_t dma_tag; /* data buffer DMA tag */
bus_dma_tag_t ioctl_tag; /* ioctl data buffer DMA tag */
bus_dmamap_t cmd_map; /* DMA map for CL's DMA'able mem */
bus_dmamap_t ioctl_map; /* DMA map for ioctl data buffers */
#ifdef TW_OSL_FLASH_FIRMWARE
bus_dma_tag_t flash_tag;/* DMA tag for CL's fw flash mem */
bus_dmamap_t flash_map;/* DMA map for CL's fw flash mem */
#endif /* TW_OSL_FLASH_FIRMWARE */
struct resource *irq_res; /* interrupt resource */
TW_INT32 irq_res_id; /* register resource id */
TW_VOID *intr_handle; /* interrupt handle */
struct sysctl_ctx_list sysctl_ctxt; /* sysctl context */
struct sysctl_oid *sysctl_tree; /* sysctl oid */
struct cam_sim *sim; /* sim for this controller */
struct cam_path *path; /* peripheral, path, tgt, lun
associated with this controller */
};
/*
* Queue primitives.
*/
#ifdef TW_OSL_DEBUG
#define TW_OSLI_Q_INIT(sc, q_type) do { \
(sc)->q_stats[q_type].cur_len = 0; \
(sc)->q_stats[q_type].max_len = 0; \
} while(0)
#define TW_OSLI_Q_INSERT(sc, q_type) do { \
struct tw_osli_q_stats *q_stats = &((sc)->q_stats[q_type]); \
\
if (++(q_stats->cur_len) > q_stats->max_len) \
q_stats->max_len = q_stats->cur_len; \
} while(0)
#define TW_OSLI_Q_REMOVE(sc, q_type) \
(sc)->q_stats[q_type].cur_len--
#else /* TW_OSL_DEBUG */
#define TW_OSLI_Q_INIT(sc, q_index)
#define TW_OSLI_Q_INSERT(sc, q_index)
#define TW_OSLI_Q_REMOVE(sc, q_index)
#endif /* TW_OSL_DEBUG */
/* Initialize a queue of requests. */
static __inline TW_VOID
tw_osli_req_q_init(struct twa_softc *sc, TW_UINT8 q_type)
{
TW_CL_Q_INIT(&(sc->req_q_head[q_type]));
TW_OSLI_Q_INIT(sc, q_type);
}
/* Insert the given request at the head of the given queue (q_type). */
static __inline TW_VOID
tw_osli_req_q_insert_head(struct tw_osli_req_context *req, TW_UINT8 q_type)
{
mtx_lock_spin(req->ctlr->q_lock);
TW_CL_Q_INSERT_HEAD(&(req->ctlr->req_q_head[q_type]), &(req->link));
TW_OSLI_Q_INSERT(req->ctlr, q_type);
mtx_unlock_spin(req->ctlr->q_lock);
}
/* Insert the given request at the tail of the given queue (q_type). */
static __inline TW_VOID
tw_osli_req_q_insert_tail(struct tw_osli_req_context *req, TW_UINT8 q_type)
{
mtx_lock_spin(req->ctlr->q_lock);
TW_CL_Q_INSERT_TAIL(&(req->ctlr->req_q_head[q_type]), &(req->link));
TW_OSLI_Q_INSERT(req->ctlr, q_type);
mtx_unlock_spin(req->ctlr->q_lock);
}
/* Remove and return the request at the head of the given queue (q_type). */
static __inline struct tw_osli_req_context *
tw_osli_req_q_remove_head(struct twa_softc *sc, TW_UINT8 q_type)
{
struct tw_osli_req_context *req = NULL;
struct tw_cl_link *link;
mtx_lock_spin(sc->q_lock);
if ((link = TW_CL_Q_FIRST_ITEM(&(sc->req_q_head[q_type]))) !=
TW_CL_NULL) {
req = TW_CL_STRUCT_HEAD(link,
struct tw_osli_req_context, link);
TW_CL_Q_REMOVE_ITEM(&(sc->req_q_head[q_type]), &(req->link));
TW_OSLI_Q_REMOVE(sc, q_type);
}
mtx_unlock_spin(sc->q_lock);
return(req);
}
/* Remove the given request from the given queue (q_type). */
static __inline TW_VOID
tw_osli_req_q_remove_item(struct tw_osli_req_context *req, TW_UINT8 q_type)
{
mtx_lock_spin(req->ctlr->q_lock);
TW_CL_Q_REMOVE_ITEM(&(req->ctlr->req_q_head[q_type]), &(req->link));
TW_OSLI_Q_REMOVE(req->ctlr, q_type);
mtx_unlock_spin(req->ctlr->q_lock);
}
#ifdef TW_OSL_DEBUG
extern TW_INT32 TW_DEBUG_LEVEL_FOR_OSL;
#define tw_osli_dbg_dprintf(dbg_level, sc, fmt, args...) \
if (dbg_level <= TW_DEBUG_LEVEL_FOR_OSL) \
device_printf(sc->bus_dev, "%s: " fmt "\n", \
__func__, ##args)
#define tw_osli_dbg_printf(dbg_level, fmt, args...) \
if (dbg_level <= TW_DEBUG_LEVEL_FOR_OSL) \
printf("%s: " fmt "\n", __func__, ##args)
#else /* TW_OSL_DEBUG */
#define tw_osli_dbg_dprintf(dbg_level, sc, fmt, args...)
#define tw_osli_dbg_printf(dbg_level, fmt, args...)
#endif /* TW_OSL_DEBUG */
/* For regular printing. */
#define twa_printf(sc, fmt, args...) \
device_printf(((struct twa_softc *)(sc))->bus_dev, fmt, ##args)
/* For printing in the "consistent error reporting" format. */
#define tw_osli_printf(sc, err_specific_desc, args...) \
device_printf((sc)->bus_dev, \
"%s: (0x%02X: 0x%04X): %s: " err_specific_desc "\n", ##args)
#endif /* TW_OSL_H */

761
sys/dev/twa/tw_osl_cam.c Normal file
View File

@ -0,0 +1,761 @@
/*
* 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
*/
/*
* FreeBSD CAM related functions.
*/
#include "tw_osl_includes.h"
#include <cam/cam.h>
#include <cam/cam_ccb.h>
#include <cam/cam_sim.h>
#include <cam/cam_xpt_sim.h>
#include <cam/cam_xpt_periph.h>
#include <cam/cam_debug.h>
#include <cam/cam_periph.h>
#include <cam/scsi/scsi_all.h>
#include <cam/scsi/scsi_message.h>
static TW_VOID twa_action(struct cam_sim *sim, union ccb *ccb);
static TW_VOID twa_poll(struct cam_sim *sim);
static TW_VOID twa_async(TW_VOID *callback_arg, TW_UINT32 code,
struct cam_path *path, TW_VOID *arg);
static TW_VOID twa_timeout(TW_VOID *arg);
static TW_VOID twa_bus_scan_cb(struct cam_periph *periph, union ccb *ccb);
static TW_INT32 tw_osli_execute_scsi(struct tw_osli_req_context *req,
union ccb *ccb);
/*
* Function name: tw_osli_cam_attach
* Description: Attaches the driver to CAM.
*
* Input: sc -- ptr to OSL internal ctlr context
* Output: None
* Return value: 0 -- success
* non-zero-- failure
*/
TW_INT32
tw_osli_cam_attach(struct twa_softc *sc)
{
struct cam_devq *devq;
struct ccb_setasync csa;
TW_INT32 error;
tw_osli_dbg_dprintf(3, sc, "entered");
/*
* Create the device queue for our SIM.
*/
if ((devq = cam_simq_alloc(TW_OSLI_MAX_NUM_IOS)) == NULL) {
tw_osli_printf(sc, "error = %d",
TW_CL_SEVERITY_ERROR_STRING,
TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
0x2100,
"Failed to create SIM device queue",
ENOMEM);
return(ENOMEM);
}
/*
* Create a SIM entry. Though we can support TW_OSLI_MAX_NUM_IOS
* simultaneous requests, we claim to be able to handle only
* (TW_OSLI_MAX_NUM_IOS - 1), so that we always have a request
* packet available to service ioctls.
*/
tw_osli_dbg_dprintf(3, sc, "Calling cam_sim_alloc");
sc->sim = cam_sim_alloc(twa_action, twa_poll, "twa", sc,
device_get_unit(sc->bus_dev),
TW_OSLI_MAX_NUM_IOS - 1, 1, devq);
if (sc->sim == NULL) {
cam_simq_free(devq);
tw_osli_printf(sc, "error = %d",
TW_CL_SEVERITY_ERROR_STRING,
TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
0x2101,
"Failed to create a SIM entry",
ENOMEM);
return(ENOMEM);
}
/*
* Register the bus.
*/
tw_osli_dbg_dprintf(3, sc, "Calling xpt_bus_register");
if (xpt_bus_register(sc->sim, 0) != CAM_SUCCESS) {
cam_sim_free(sc->sim, TRUE);
sc->sim = NULL; /* so cam_detach will not try to free it */
tw_osli_printf(sc, "error = %d",
TW_CL_SEVERITY_ERROR_STRING,
TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
0x2102,
"Failed to register the bus",
ENXIO);
return(ENXIO);
}
tw_osli_dbg_dprintf(3, sc, "Calling xpt_create_path");
if (xpt_create_path(&sc->path, NULL,
cam_sim_path(sc->sim),
CAM_TARGET_WILDCARD,
CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
xpt_bus_deregister(cam_sim_path (sc->sim));
/* Passing TRUE to cam_sim_free will free the devq as well. */
cam_sim_free(sc->sim, TRUE);
tw_osli_printf(sc, "error = %d",
TW_CL_SEVERITY_ERROR_STRING,
TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
0x2103,
"Failed to create path",
ENXIO);
return(ENXIO);
}
tw_osli_dbg_dprintf(3, sc, "Calling xpt_setup_ccb");
xpt_setup_ccb(&csa.ccb_h, sc->path, 5);
csa.ccb_h.func_code = XPT_SASYNC_CB;
csa.event_enable = AC_FOUND_DEVICE | AC_LOST_DEVICE;
csa.callback = twa_async;
csa.callback_arg = sc;
xpt_action((union ccb *)&csa);
tw_osli_dbg_dprintf(3, sc, "Calling tw_osli_request_bus_scan");
/*
* Request a bus scan, so that CAM gets to know of
* the logical units that we control.
*/
if ((error = tw_osli_request_bus_scan(sc)))
tw_osli_printf(sc, "error = %d",
TW_CL_SEVERITY_ERROR_STRING,
TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
0x2104,
"Bus scan request to CAM failed",
error);
tw_osli_dbg_dprintf(3, sc, "exiting");
return(0);
}
/*
* Function name: tw_osli_cam_detach
* Description: Detaches the driver from CAM.
*
* Input: sc -- ptr to OSL internal ctlr context
* Output: None
* Return value: None
*/
TW_VOID
tw_osli_cam_detach(struct twa_softc *sc)
{
tw_osli_dbg_dprintf(3, sc, "entered");
if (sc->path)
xpt_free_path(sc->path);
if (sc->sim) {
xpt_bus_deregister(cam_sim_path(sc->sim));
/* Passing TRUE to cam_sim_free will free the devq as well. */
cam_sim_free(sc->sim, TRUE);
}
}
/*
* Function name: tw_osli_execute_scsi
* Description: Build a fw cmd, based on a CAM style ccb, and
* send it down.
*
* Input: req -- ptr to OSL internal request context
* ccb -- ptr to CAM style ccb
* Output: None
* Return value: 0 -- success
* non-zero-- failure
*/
TW_INT32
tw_osli_execute_scsi(struct tw_osli_req_context *req, union ccb *ccb)
{
struct twa_softc *sc = req->ctlr;
struct tw_cl_req_packet *req_pkt;
struct tw_cl_scsi_req_packet *scsi_req;
struct ccb_hdr *ccb_h = &(ccb->ccb_h);
struct ccb_scsiio *csio = &(ccb->csio);
TW_INT32 error;
tw_osli_dbg_dprintf(10, sc, "SCSI I/O request 0x%x",
csio->cdb_io.cdb_bytes[0]);
if (ccb_h->target_id >= TW_CL_MAX_NUM_UNITS) {
tw_osli_dbg_dprintf(3, sc, "Invalid target. PTL = %x %x %x",
ccb_h->path_id, ccb_h->target_id, ccb_h->target_lun);
ccb_h->status |= CAM_TID_INVALID;
xpt_done(ccb);
return(1);
}
if (ccb_h->target_lun >= TW_CL_MAX_NUM_LUNS) {
tw_osli_dbg_dprintf(3, sc, "Invalid lun. PTL = %x %x %x",
ccb_h->path_id, ccb_h->target_id, ccb_h->target_lun);
ccb_h->status |= CAM_LUN_INVALID;
xpt_done(ccb);
return(1);
}
if(ccb_h->flags & CAM_CDB_PHYS) {
tw_osli_printf(sc, "",
TW_CL_SEVERITY_ERROR_STRING,
TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
0x2105,
"Physical CDB address!");
ccb_h->status = CAM_REQ_CMP_ERR;
xpt_done(ccb);
return(1);
}
/*
* We are going to work on this request. Mark it as enqueued (though
* we don't actually queue it...)
*/
ccb_h->status |= CAM_SIM_QUEUED;
if((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
if(ccb_h->flags & CAM_DIR_IN)
req->flags |= TW_OSLI_REQ_FLAGS_DATA_IN;
else
req->flags |= TW_OSLI_REQ_FLAGS_DATA_OUT;
}
/* Build the CL understood request packet for SCSI cmds. */
req_pkt = &req->req_pkt;
req_pkt->status = 0;
req_pkt->tw_osl_callback = tw_osl_complete_io;
scsi_req = &(req_pkt->gen_req_pkt.scsi_req);
scsi_req->unit = ccb_h->target_id;
scsi_req->lun = ccb_h->target_lun;
scsi_req->sense_len = 0;
scsi_req->sense_data = (TW_UINT8 *)(&csio->sense_data);
scsi_req->scsi_status = 0;
if(ccb_h->flags & CAM_CDB_POINTER)
scsi_req->cdb = csio->cdb_io.cdb_ptr;
else
scsi_req->cdb = csio->cdb_io.cdb_bytes;
scsi_req->cdb_len = csio->cdb_len;
if (!(ccb_h->flags & CAM_DATA_PHYS)) {
/* Virtual data addresses. Need to convert them... */
tw_osli_dbg_dprintf(3, sc,
"XPT_SCSI_IO: Single virtual address!");
if (!(ccb_h->flags & CAM_SCATTER_VALID)) {
if (csio->dxfer_len > TW_CL_MAX_IO_SIZE) {
tw_osli_printf(sc, "size = %d",
TW_CL_SEVERITY_ERROR_STRING,
TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
0x2106,
"I/O size too big",
csio->dxfer_len);
ccb_h->status = CAM_REQ_TOO_BIG;
xpt_done(ccb);
return(1);
}
if ((req->length = csio->dxfer_len)) {
req->data = csio->data_ptr;
scsi_req->sgl_entries = 1;
}
} else {
tw_osli_printf(sc, "",
TW_CL_SEVERITY_ERROR_STRING,
TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
0x2107,
"XPT_SCSI_IO: Got SGList");
ccb_h->status = CAM_REQ_CMP_ERR;
xpt_done(ccb);
return(1);
}
} else {
/* Data addresses are physical. */
tw_osli_printf(sc, "",
TW_CL_SEVERITY_ERROR_STRING,
TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
0x2108,
"XPT_SCSI_IO: Physical data addresses");
ccb_h->status = CAM_REQ_CMP_ERR;
ccb_h->status |= CAM_RELEASE_SIMQ;
ccb_h->status &= ~CAM_SIM_QUEUED;
xpt_done(ccb);
return(1);
}
ccb_h->timeout_ch = timeout(twa_timeout, req,
(ccb_h->timeout * hz) / 1000);
/*
* twa_map_load_data_callback will fill in the SGL,
* and submit the I/O.
*/
error = tw_osli_map_request(req);
return(error);
}
/*
* Function name: twa_action
* Description: Driver entry point for CAM's use.
*
* Input: sim -- sim corresponding to the ctlr
* ccb -- ptr to CAM request
* Output: None
* Return value: None
*/
TW_VOID
twa_action(struct cam_sim *sim, union ccb *ccb)
{
struct twa_softc *sc = (struct twa_softc *)cam_sim_softc(sim);
struct ccb_hdr *ccb_h = &(ccb->ccb_h);
switch (ccb_h->func_code) {
case XPT_SCSI_IO: /* SCSI I/O */
{
struct tw_osli_req_context *req;
if ((sc->state & TW_OSLI_CTLR_STATE_SIMQ_FROZEN) ||
((req = tw_osli_get_request(sc)) == NULL)) {
tw_osli_dbg_dprintf(2, sc,
"simq frozen/Cannot get request pkt.");
/*
* Freeze the simq to maintain ccb ordering. The next
* ccb that gets completed will unfreeze the simq.
*/
tw_osli_disallow_new_requests(sc);
ccb_h->status |= CAM_REQUEUE_REQ;
xpt_done(ccb);
break;
}
req->req_handle.osl_req_ctxt = req;
req->orig_req = ccb;
if (tw_osli_execute_scsi(req, ccb))
tw_osli_req_q_insert_tail(req, TW_OSLI_FREE_Q);
break;
}
case XPT_ABORT:
tw_osli_dbg_dprintf(2, sc, "Abort request.");
ccb_h->status = CAM_UA_ABORT;
xpt_done(ccb);
break;
case XPT_RESET_BUS:
tw_cl_create_event(&(sc->ctlr_handle), TW_CL_TRUE,
TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
0x2108, 0x3, TW_CL_SEVERITY_INFO_STRING,
"Received Reset Bus request from CAM",
" ");
if (tw_cl_reset_ctlr(&sc->ctlr_handle)) {
tw_cl_create_event(&(sc->ctlr_handle), TW_CL_TRUE,
TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
0x2109, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"Failed to reset bus",
" ");
ccb_h->status = CAM_REQ_CMP_ERR;
}
else
ccb_h->status = CAM_REQ_CMP;
xpt_done(ccb);
break;
case XPT_SET_TRAN_SETTINGS:
tw_osli_dbg_dprintf(3, sc, "XPT_SET_TRAN_SETTINGS");
/*
* This command is not supported, since it's very specific
* to SCSI, and we are doing ATA.
*/
ccb_h->status = CAM_FUNC_NOTAVAIL;
xpt_done(ccb);
break;
case XPT_GET_TRAN_SETTINGS:
{
struct ccb_trans_settings *cts = &ccb->cts;
tw_osli_dbg_dprintf(3, sc, "XPT_GET_TRAN_SETTINGS");
cts->valid = (CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID);
cts->flags &= ~(CCB_TRANS_DISC_ENB | CCB_TRANS_TAG_ENB);
ccb_h->status = CAM_REQ_CMP;
xpt_done(ccb);
break;
}
case XPT_CALC_GEOMETRY:
tw_osli_dbg_dprintf(3, sc, "XPT_CALC_GEOMETRY");
cam_calc_geometry(&ccb->ccg, 1/* extended */);
xpt_done(ccb);
break;
case XPT_PATH_INQ: /* Path inquiry -- get twa properties */
{
struct ccb_pathinq *path_inq = &ccb->cpi;
tw_osli_dbg_dprintf(3, sc, "XPT_PATH_INQ request");
path_inq->version_num = 1;
path_inq->hba_inquiry = 0;
path_inq->target_sprt = 0;
path_inq->hba_misc = 0;
path_inq->hba_eng_cnt = 0;
path_inq->max_target = TW_CL_MAX_NUM_UNITS;
path_inq->max_lun = TW_CL_MAX_NUM_LUNS - 1;
path_inq->unit_number = cam_sim_unit(sim);
path_inq->bus_id = cam_sim_bus(sim);
path_inq->initiator_id = 12;
path_inq->base_transfer_speed = 100000;
strncpy(path_inq->sim_vid, "FreeBSD", SIM_IDLEN);
strncpy(path_inq->hba_vid, "3ware", HBA_IDLEN);
strncpy(path_inq->dev_name, cam_sim_name(sim), DEV_IDLEN);
ccb_h->status = CAM_REQ_CMP;
xpt_done(ccb);
break;
}
default:
tw_osli_dbg_dprintf(3, sc, "func_code = %x", ccb_h->func_code);
ccb_h->status = CAM_REQ_INVALID;
xpt_done(ccb);
break;
}
}
/*
* Function name: twa_poll
* Description: Driver entry point called when interrupts are not
* available.
*
* Input: sim -- sim corresponding to the controller
* Output: None
* Return value: None
*/
TW_VOID
twa_poll(struct cam_sim *sim)
{
struct twa_softc *sc = (struct twa_softc *)(cam_sim_softc(sim));
tw_osli_dbg_dprintf(3, sc, "entering; sc = %p", sc);
if (tw_cl_interrupt(&(sc->ctlr_handle)))
tw_cl_deferred_interrupt(&(sc->ctlr_handle));
tw_osli_dbg_dprintf(3, sc, "exiting; sc = %p", sc);
}
/*
* Function name: twa_async
* Description: Driver entry point for CAM to notify driver of special
* events. We don't use this for now.
*
* Input: callback_arg -- ptr to per ctlr structure
* code -- code associated with the event
* path -- cam path
* arg --
* Output: None
* Return value: 0 -- success
* non-zero-- failure
*/
TW_VOID
twa_async(TW_VOID *callback_arg, TW_UINT32 code,
struct cam_path *path, TW_VOID *arg)
{
#ifdef TW_OSL_DEBUG
struct twa_softc *sc = (struct twa_softc *)callback_arg;
#endif /* TW_OSL_DEBUG */
tw_osli_dbg_dprintf(3, sc, "sc = %p, code = %x, path = %p, arg = %p",
sc, code, path, arg);
}
/*
* Function name: twa_timeout
* Description: Driver entry point for being alerted on a request
* timing out.
*
* Input: arg -- ptr to timed out request
* Output: None
* Return value: None
*/
static TW_VOID
twa_timeout(TW_VOID *arg)
{
struct tw_osli_req_context *req =
(struct tw_osli_req_context *)arg;
tw_cl_create_event(&(req->ctlr->ctlr_handle), TW_CL_TRUE,
TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
0x210B, 0x1, TW_CL_SEVERITY_ERROR_STRING,
"Request timed out!",
"request = %p", req);
tw_cl_reset_ctlr(&(req->ctlr->ctlr_handle));
}
/*
* Function name: tw_osli_request_bus_scan
* Description: Requests CAM for a scan of the bus.
*
* Input: sc -- ptr to per ctlr structure
* Output: None
* Return value: 0 -- success
* non-zero-- failure
*/
TW_INT32
tw_osli_request_bus_scan(struct twa_softc *sc)
{
struct cam_path *path;
union ccb *ccb;
tw_osli_dbg_dprintf(3, sc, "entering");
if ((ccb = malloc(sizeof(union ccb), M_TEMP, M_WAITOK)) == NULL)
return(ENOMEM);
bzero(ccb, sizeof(union ccb));
if (xpt_create_path(&path, xpt_periph, cam_sim_path(sc->sim),
CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP)
return(EIO);
xpt_setup_ccb(&ccb->ccb_h, path, 5);
ccb->ccb_h.func_code = XPT_SCAN_BUS;
ccb->ccb_h.cbfcnp = twa_bus_scan_cb;
ccb->crcn.flags = CAM_FLAG_NONE;
xpt_action(ccb);
return(0);
}
/*
* Function name: twa_bus_scan_cb
* Description: Callback from CAM on a bus scan request.
*
* Input: periph -- we don't use this
* ccb -- bus scan request ccb that we sent to CAM
* Output: None
* Return value: None
*/
static TW_VOID
twa_bus_scan_cb(struct cam_periph *periph, union ccb *ccb)
{
tw_osli_dbg_printf(3, "entering");
if (ccb->ccb_h.status != CAM_REQ_CMP)
printf("cam_scan_callback: failure status = %x\n",
ccb->ccb_h.status);
else
tw_osli_dbg_printf(3, "success");
xpt_free_path(ccb->ccb_h.path);
free(ccb, M_TEMP);
}
/*
* Function name: tw_osli_allow_new_requests
* Description: Sets the appropriate status bits in a ccb such that,
* when the ccb is completed by a call to xpt_done,
* CAM knows that it's ok to unfreeze the flow of new
* requests to this controller, if the flow is frozen.
*
* Input: sc -- ptr to OSL internal ctlr context
* ccb -- ptr to CAM request
* Output: None
* Return value: None
*/
TW_VOID
tw_osli_allow_new_requests(struct twa_softc *sc, TW_VOID *ccb)
{
((union ccb *)(ccb))->ccb_h.status |= CAM_RELEASE_SIMQ;
sc->state &= ~TW_OSLI_CTLR_STATE_SIMQ_FROZEN;
}
/*
* Function name: tw_osli_disallow_new_requests
* Description: Calls the appropriate CAM function, so as to freeze
* the flow of new requests from CAM to this controller.
*
* Input: sc -- ptr to OSL internal ctlr context
* Output: None
* Return value: None
*/
TW_VOID
tw_osli_disallow_new_requests(struct twa_softc *sc)
{
xpt_freeze_simq(sc->sim, 1);
sc->state |= TW_OSLI_CTLR_STATE_SIMQ_FROZEN;
}
/*
* Function name: tw_osl_scan_bus
* Description: CL calls this function to request for a bus scan.
*
* Input: ctlr_handle -- ptr to controller handle
* Output: None
* Return value: None
*/
TW_VOID
tw_osl_scan_bus(struct tw_cl_ctlr_handle *ctlr_handle)
{
struct twa_softc *sc = ctlr_handle->osl_ctlr_ctxt;
TW_INT32 error;
if ((error = tw_osli_request_bus_scan(sc)))
tw_osli_printf(sc, "error = %d",
TW_CL_SEVERITY_ERROR_STRING,
TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
0x2109,
"Bus scan request to CAM failed",
error);
}
/*
* Function name: tw_osl_complete_io
* Description: Called to complete CAM scsi requests.
*
* Input: req_handle -- ptr to request handle
* Output: None
* Return value: None
*/
TW_VOID
tw_osl_complete_io(struct tw_cl_req_handle *req_handle)
{
struct tw_osli_req_context *req = req_handle->osl_req_ctxt;
struct tw_cl_req_packet *req_pkt =
(struct tw_cl_req_packet *)(&req->req_pkt);
struct tw_cl_scsi_req_packet *scsi_req;
struct twa_softc *sc = req->ctlr;
union ccb *ccb = (union ccb *)(req->orig_req);
tw_osli_dbg_dprintf(10, sc, "entering");
if (req->state != TW_OSLI_REQ_STATE_BUSY)
tw_osli_printf(sc, "request = %p, status = %d",
TW_CL_SEVERITY_ERROR_STRING,
TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
0x210A,
"Unposted command completed!!",
req, req->state);
/*
* Remove request from the busy queue. Just mark it complete.
* There's no need to move it into the complete queue as we are
* going to be done with it right now.
*/
req->state = TW_OSLI_REQ_STATE_COMPLETE;
tw_osli_req_q_remove_item(req, TW_OSLI_BUSY_Q);
tw_osli_unmap_request(req);
untimeout(twa_timeout, req, ccb->ccb_h.timeout_ch);
if (req->error_code) {
/* This request never got submitted to the firmware. */
if (req->error_code == EBUSY) {
/*
* Cmd queue is full, or common layer is out
* of resources. Freeze the simq to maintain
* ccb ordering. The next ccb that gets
* completed will unfreeze the simq.
*/
tw_osli_disallow_new_requests(req->ctlr);
ccb->ccb_h.status |= CAM_REQUEUE_REQ;
}
else if (req->error_code == EFBIG)
ccb->ccb_h.status = CAM_REQ_TOO_BIG;
else
ccb->ccb_h.status = CAM_REQ_CMP_ERR;
} else {
scsi_req = &(req_pkt->gen_req_pkt.scsi_req);
if (req_pkt->status == TW_CL_ERR_REQ_SUCCESS)
ccb->ccb_h.status = CAM_REQ_CMP;
else {
if (req_pkt->status & TW_CL_ERR_REQ_INVALID_TARGET)
ccb->ccb_h.status |= CAM_TID_INVALID;
else if (req_pkt->status & TW_CL_ERR_REQ_INVALID_LUN)
ccb->ccb_h.status |= CAM_LUN_INVALID;
else if (req_pkt->status & TW_CL_ERR_REQ_SCSI_ERROR)
ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
else if (req_pkt->status & TW_CL_ERR_REQ_BUS_RESET)
ccb->ccb_h.status |= CAM_SCSI_BUS_RESET;
/*
* If none of the above errors occurred, simply
* mark completion error.
*/
if (ccb->ccb_h.status == 0)
ccb->ccb_h.status = CAM_REQ_CMP_ERR;
if (req_pkt->status & TW_CL_ERR_REQ_AUTO_SENSE_VALID) {
ccb->csio.sense_len = scsi_req->sense_len;
ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
}
}
ccb->csio.scsi_status = scsi_req->scsi_status;
/* If simq is frozen, unfreeze it. */
if (sc->state & TW_OSLI_CTLR_STATE_SIMQ_FROZEN)
tw_osli_allow_new_requests(sc, (TW_VOID *)ccb);
}
ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
xpt_done(ccb);
if (! req->error_code)
/* twa_action will free the request otherwise */
tw_osli_req_q_insert_tail(req, TW_OSLI_FREE_Q);
}

View File

@ -0,0 +1,95 @@
/*
* 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
*/
#ifndef TW_OSL_EXTERNS_H
#define TW_OSL_EXTERNS_H
/*
* Data structures and functions global to the OS Layer.
*/
/* External data structures. */
extern int mp_ncpus;
/* Functions in tw_osl_freebsd.c */
/* Build a firmware passthru cmd pkt, and submit it to CL. */
extern TW_INT32 tw_osli_fw_passthru(struct twa_softc *sc, TW_INT8 *buf);
/* Get an OSL internal request context packet. */
extern struct tw_osli_req_context *tw_osli_get_request(struct twa_softc *sc);
/* Map data to DMA'able memory. */
extern TW_INT32 tw_osli_map_request(struct tw_osli_req_context *req);
/* Undo mapping. */
extern TW_VOID tw_osli_unmap_request(struct tw_osli_req_context *req);
/* Functions in tw_osl_cam.c */
/* Attach to CAM. */
extern TW_INT32 tw_osli_cam_attach(struct twa_softc *sc);
/* Detach from CAM. */
extern TW_VOID tw_osli_cam_detach(struct twa_softc *sc);
/* Request CAM for a bus scan. */
extern TW_INT32 tw_osli_request_bus_scan(struct twa_softc *sc);
/* Unfreeze ccb flow from CAM. */
extern TW_VOID tw_osli_allow_new_requests(struct twa_softc *sc, TW_VOID *ccb);
/* Freeze ccb flow from CAM. */
extern TW_VOID tw_osli_disallow_new_requests(struct twa_softc *sc);
/* OSL's completion routine for SCSI I/O's. */
extern TW_VOID tw_osl_complete_io(struct tw_cl_req_handle *req_handle);
/* OSL's completion routine for passthru requests. */
extern TW_VOID tw_osl_complete_passthru(struct tw_cl_req_handle *req_handle);
#endif /* TW_OSL_EXTERNS_H */

1983
sys/dev/twa/tw_osl_freebsd.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
/*-
* Copyright (c) 2003-04 3ware, Inc.
/*
* 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
@ -27,15 +28,25 @@
*/
/*
* 3ware driver for 9000 series storage controllers.
* AMCC'S 3ware driver for 9000 series storage controllers.
*
* Author: Vinod Kashyap
*/
#ifndef TW_OSL_INCLUDES_H
#define TW_OSL_INCLUDES_H
/*
* All header files needed by the OS Layer.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/libkern.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/module.h>
@ -45,10 +56,12 @@
#include <sys/disk.h>
#include <sys/stat.h>
#include <sys/devicestat.h>
#include <sys/taskqueue.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <machine/clock.h>
#include <machine/stdarg.h>
#include <vm/vm.h>
@ -57,8 +70,11 @@
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <opt_twa.h>
#include <dev/twa/twa_reg.h>
#include <dev/twa/twa_ioctl.h>
#include <dev/twa/twa.h>
#include <dev/twa/twa_externs.h>
#include "tw_osl_share.h"
#include "tw_cl_share.h"
#include "tw_osl.h"
#include "tw_osl_externs.h"
#endif /* TW_OSL_INCLUDES_H */

115
sys/dev/twa/tw_osl_ioctl.h Normal file
View File

@ -0,0 +1,115 @@
/*
* 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
*/
#ifndef TW_OSL_IOCTL_H
#define TW_OSL_IOCTL_H
/*
* Macros and structures for OS Layer/Common Layer handled ioctls.
*/
#include "tw_cl_fwif.h"
#include "tw_cl_ioctl.h"
#pragma pack(1)
/*
* We need the structure below to ensure that the first byte of
* data_buf is not overwritten by the kernel, after we return
* from the ioctl call. Note that cmd_pkt has been reduced
* to an array of 1024 bytes even though it's actually 2048 bytes
* in size. This is because, we don't expect requests from user
* land requiring 2048 (273 sg elements) byte cmd pkts.
*/
typedef struct tw_osli_ioctl_no_data_buf {
struct tw_cl_driver_packet driver_pkt;
TW_VOID *pdata; /* points to data_buf */
TW_INT8 padding[488 - sizeof(TW_VOID *)];
struct tw_cl_command_packet cmd_pkt;
} TW_OSLI_IOCTL_NO_DATA_BUF;
#pragma pack()
/* ioctl cmds handled by the OS Layer */
#define TW_OSL_IOCTL_SCAN_BUS \
_IO('T', 200)
#define TW_OSL_IOCTL_FIRMWARE_PASS_THROUGH \
_IOWR('T', 202, TW_OSLI_IOCTL_NO_DATA_BUF)
#include <sys/ioccom.h>
#pragma pack(1)
typedef struct tw_osli_ioctl_with_payload {
struct tw_cl_driver_packet driver_pkt;
TW_INT8 padding[488];
struct tw_cl_command_packet cmd_pkt;
union {
struct tw_cl_event_packet event_pkt;
struct tw_cl_lock_packet lock_pkt;
struct tw_cl_compatibility_packet compat_pkt;
TW_INT8 data_buf[1];
} payload;
} TW_OSLI_IOCTL_WITH_PAYLOAD;
#pragma pack()
/* ioctl cmds handled by the Common Layer */
#define TW_CL_IOCTL_GET_FIRST_EVENT \
_IOWR('T', 203, TW_OSLI_IOCTL_WITH_PAYLOAD)
#define TW_CL_IOCTL_GET_LAST_EVENT \
_IOWR('T', 204, TW_OSLI_IOCTL_WITH_PAYLOAD)
#define TW_CL_IOCTL_GET_NEXT_EVENT \
_IOWR('T', 205, TW_OSLI_IOCTL_WITH_PAYLOAD)
#define TW_CL_IOCTL_GET_PREVIOUS_EVENT \
_IOWR('T', 206, TW_OSLI_IOCTL_WITH_PAYLOAD)
#define TW_CL_IOCTL_GET_LOCK \
_IOWR('T', 207, TW_OSLI_IOCTL_WITH_PAYLOAD)
#define TW_CL_IOCTL_RELEASE_LOCK \
_IOWR('T', 208, TW_OSLI_IOCTL_WITH_PAYLOAD)
#define TW_CL_IOCTL_GET_COMPATIBILITY_INFO \
_IOWR('T', 209, TW_OSLI_IOCTL_WITH_PAYLOAD)
#endif /* TW_OSL_IOCTL_H */

134
sys/dev/twa/tw_osl_share.h Normal file
View File

@ -0,0 +1,134 @@
/*
* 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
*/
#ifndef TW_OSL_SHARE_H
#define TW_OSL_SHARE_H
/*
* Macros, structures and functions shared between OSL and CL,
* and defined by OSL.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <machine/endian.h>
#include <machine/stdarg.h>
#include "tw_osl_types.h"
#include "opt_twa.h"
#ifdef TWA_DEBUG
#define TW_OSL_DEBUG TWA_DEBUG
#endif
#ifdef TWA_FLASH_FIRMWARE
#define TW_OSL_FLASH_FIRMWARE
#endif
#define TW_OSL_DRIVER_VERSION_STRING "3.60.00.016"
#define TW_OSL_CAN_SLEEP
#ifdef TW_OSL_CAN_SLEEP
typedef TW_VOID *TW_SLEEP_HANDLE;
#endif /* TW_OSL_CAN_SLEEP */
/*#define TW_OSL_DMA_MEM_ALLOC_PER_REQUEST*/
#define TW_OSL_PCI_CONFIG_ACCESSIBLE
#if _BYTE_ORDER == _BIG_ENDIAN
#define TW_OSL_BIG_ENDIAN
#else
#define TW_OSL_LITTLE_ENDIAN
#endif
#ifdef TW_OSL_DEBUG
extern TW_INT32 TW_OSL_DEBUG_LEVEL_FOR_CL;
#endif /* TW_OSL_DEBUG */
/* Possible return codes from/to Common Layer functions. */
#define TW_OSL_ESUCCESS 0 /* success */
#define TW_OSL_EGENFAILURE 1 /* general failure */
#define TW_OSL_ENOMEM ENOMEM /* insufficient memory */
#define TW_OSL_EIO EIO /* I/O error */
#define TW_OSL_ETIMEDOUT ETIMEDOUT /* time out */
#define TW_OSL_ENOTTY ENOTTY /* invalid command */
#define TW_OSL_EBUSY EBUSY /* busy -- try later */
#define TW_OSL_EBIG EFBIG /* request too big */
#define TW_OSL_EWOULDBLOCK EWOULDBLOCK /* sleep timed out */
#define TW_OSL_ERESTART ERESTART /* sleep terminated by a signal */
#define tw_osl_breakpoint() breakpoint
#define tw_osl_cur_func() __func__
/*
* Submit any requests previously returned with TW_OSL_EBUSY.
* We don't use it as of now.
*/
#define tw_osl_ctlr_ready(ctlr_handle)
#define tw_osl_destroy_lock(ctlr_handle, lock) \
mtx_destroy(lock)
#define tw_osl_free_lock(ctlr_handle, lock) \
mtx_unlock_spin(lock)
#define tw_osl_get_lock(ctlr_handle, lock) \
mtx_lock_spin(lock)
#define tw_osl_init_lock(ctlr_handle, lock_name, lock) \
mtx_init(lock, lock_name, NULL, MTX_SPIN)
#define tw_osl_memcpy(dest, src, size) bcopy(src, dest, size)
#define tw_osl_memzero bzero
#define tw_osl_sprintf sprintf
#define tw_osl_strcpy strcpy
#define tw_osl_strlen strlen
#define tw_osl_vsprintf vsprintf
#endif /* TW_OSL_SHARE_H */

View File

@ -0,0 +1,63 @@
/*
* 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
*/
#ifndef TW_OSL_TYPES_H
#define TW_OSL_TYPES_H
/*
* typedefs shared between OSL and CL, and defined by OSL.
*/
typedef void TW_VOID;
typedef char TW_INT8;
typedef unsigned char TW_UINT8;
typedef short TW_INT16;
typedef unsigned short TW_UINT16;
typedef int TW_INT32;
typedef unsigned int TW_UINT32;
typedef long long TW_INT64;
typedef unsigned long long TW_UINT64;
typedef time_t TW_TIME;
typedef struct mtx TW_LOCK_HANDLE;
#endif /* TW_OSL_TYPES_H */

File diff suppressed because it is too large Load Diff

View File

@ -1,320 +0,0 @@
/*-
* Copyright (c) 2003-04 3ware, Inc.
* Copyright (c) 2000 Michael Smith
* Copyright (c) 2000 BSDi
* 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$
*/
/*
* 3ware driver for 9000 series storage controllers.
*
* Author: Vinod Kashyap
*/
#define TWA_DRIVER_VERSION_STRING "2.50.02.012"
#define TWA_REQUEST_TIMEOUT_PERIOD 60 /* seconds */
#define TWA_MESSAGE_SOURCE_CONTROLLER_ERROR 3
#define TWA_MESSAGE_SOURCE_CONTROLLER_EVENT 4
#define TWA_MESSAGE_SOURCE_FREEBSD_DRIVER 6
#define TWA_MESSAGE_SOURCE_FREEBSD_OS 9
#define TWA_MALLOC_CLASS M_TWA
/* Macros for bus-space calls. */
#define TWA_READ_REGISTER(sc, offset) \
(u_int32_t)bus_space_read_4(sc->twa_bus_tag, sc->twa_bus_handle, offset)
#define TWA_WRITE_REGISTER(sc, offset, val) \
bus_space_write_4(sc->twa_bus_tag, sc->twa_bus_handle, offset, (u_int32_t)val)
/* Possible values of tr->tr_status. */
#define TWA_CMD_SETUP 0x0 /* being assembled */
#define TWA_CMD_BUSY 0x1 /* submitted to controller */
#define TWA_CMD_PENDING 0x2 /* in pending queue */
#define TWA_CMD_COMPLETE 0x3 /* completed by controller (maybe with error) */
/* Possible values of tr->tr_flags. */
#define TWA_CMD_DATA_IN (1<<0) /* read request */
#define TWA_CMD_DATA_OUT (1<<1) /* write request */
#define TWA_CMD_DATA_COPY_NEEDED (1<<2) /* data in ccb is misaligned, have to copy to/from private buffer */
#define TWA_CMD_SLEEP_ON_REQUEST (1<<3) /* owner is sleeping on this command */
#define TWA_CMD_MAPPED (1<<4) /* request has been mapped */
#define TWA_CMD_IN_PROGRESS (1<<5) /* bus_dmamap_load returned EINPROGRESS */
#define TWA_CMD_TIMER_SET (1<<6) /* request is being timed */
/* Possible values of tr->tr_cmd_pkt_type. */
#define TWA_CMD_PKT_TYPE_7K (1<<0)
#define TWA_CMD_PKT_TYPE_9K (1<<1)
#define TWA_CMD_PKT_TYPE_INTERNAL (1<<2)
#define TWA_CMD_PKT_TYPE_IOCTL (1<<3)
#define TWA_CMD_PKT_TYPE_EXTERNAL (1<<4)
/* Possible values of sc->twa_state. */
#define TWA_STATE_INTR_ENABLED (1<<0) /* interrupts have been enabled */
#define TWA_STATE_SHUTDOWN (1<<1) /* controller is shut down */
#define TWA_STATE_OPEN (1<<2) /* control device is open */
#define TWA_STATE_SUSPEND (1<<3) /* controller is suspended */
#define TWA_STATE_SIMQ_FROZEN (1<<4) /* simq frozen */
/* Possible values of sc->twa_ioctl_lock.lock. */
#define TWA_LOCK_FREE 0x0 /* lock is free */
#define TWA_LOCK_HELD 0x1 /* lock is held */
/* Error/AEN message structure. */
struct twa_message {
u_int32_t code;
char *message;
};
#ifdef TWA_DEBUG
struct twa_q_statistics {
u_int32_t q_length;
u_int32_t q_max;
};
#define TWAQ_FREE 0
#define TWAQ_BUSY 1
#define TWAQ_PENDING 2
#define TWAQ_COMPLETE 3
#define TWAQ_COUNT 4 /* total number of queues */
#endif /* TWA_DEBUG */
/* Driver's request packet. */
struct twa_request {
struct twa_command_packet *tr_command; /* ptr to cmd pkt submitted to controller */
u_int32_t tr_request_id; /* request id for tracking with firmware */
void *tr_data; /* ptr to data being passed to firmware */
u_int32_t tr_length; /* length of buffer being passed to firmware */
void *tr_real_data; /* ptr to, and length of data passed */
u_int32_t tr_real_length; /* to us from above, in case a buffer copy
was done due to non-compliance to
alignment requirements */
TAILQ_ENTRY(twa_request) tr_link; /* to link this request in a list */
struct twa_softc *tr_sc; /* controller that owns us */
u_int32_t tr_status; /* command status */
u_int32_t tr_flags; /* request flags */
u_int32_t tr_error; /* error encountered before request submission */
u_int32_t tr_cmd_pkt_type;/* type of request */
void *tr_private; /* request specific data to use during callback */
void (*tr_callback)(struct twa_request *tr);/* callback handler */
bus_addr_t tr_cmd_phys; /* physical address of command in controller space */
bus_dmamap_t tr_buf_map; /* DMA map for data */
} __attribute__ ((packed));
/* Per-controller structure. */
struct twa_softc {
/* Request queues and arrays. */
TAILQ_HEAD(, twa_request) twa_free; /* free request packets */
TAILQ_HEAD(, twa_request) twa_busy; /* requests busy in the controller */
TAILQ_HEAD(, twa_request) twa_pending; /* internal requests pending */
TAILQ_HEAD(, twa_request) twa_complete; /* requests completed by firmware (not by us) */
struct twa_request *twa_lookup[TWA_Q_LENGTH];/* requests indexed by request_id */
struct twa_request *twa_req_buf;
struct twa_command_packet *twa_cmd_pkt_buf;
/* AEN handler fields. */
struct twa_event_packet *twa_aen_queue[TWA_Q_LENGTH];/* circular queue of AENs from firmware */
uint16_t working_srl; /* driver & firmware negotiated srl */
uint16_t working_branch; /* branch # of the firmware that the driver is compatible with */
uint16_t working_build; /* build # of the firmware that the driver is compatible with */
u_int32_t twa_operating_mode; /* base mode/current mode */
u_int32_t twa_aen_head; /* AEN queue head */
u_int32_t twa_aen_tail; /* AEN queue tail */
u_int32_t twa_current_sequence_id;/* index of the last event + 1 */
u_int32_t twa_aen_queue_overflow; /* indicates if unretrieved events were overwritten */
u_int32_t twa_aen_queue_wrapped; /* indicates if AEN queue ever wrapped */
u_int32_t twa_wait_timeout; /* identifier for calling tsleep */
/* Controller state. */
u_int32_t twa_state;
#ifdef TWA_DEBUG
struct twa_q_statistics twa_qstats[TWAQ_COUNT]; /* queue statistics */
#endif /* TWA_DEBUG */
struct {
u_int32_t lock; /* lock state */
u_int32_t timeout;/* time at which the lock will become available,
even if not released */
} twa_ioctl_lock; /* lock for use by user applications, for synchronization
between ioctl calls */
device_t twa_bus_dev; /* bus device */
struct cdev *twa_ctrl_dev; /* control device */
struct resource *twa_io_res; /* register interface window */
bus_space_handle_t twa_bus_handle; /* bus space handle */
bus_space_tag_t twa_bus_tag; /* bus space tag */
bus_dma_tag_t twa_parent_tag; /* parent DMA tag */
bus_dma_tag_t twa_cmd_tag; /* cmd DMA tag */
bus_dma_tag_t twa_buf_tag; /* data buffer DMA tag */
bus_dmamap_t twa_cmd_map; /* DMA map for the array of cmd pkts */
bus_addr_t twa_cmd_pkt_phys;/* phys addr of first of array of cmd pkts */
struct resource *twa_irq_res; /* interrupt resource*/
void *twa_intr_handle;/* interrupt handle */
struct intr_config_hook twa_ich; /* delayed-startup hook */
struct sysctl_ctx_list twa_sysctl_ctx;
struct sysctl_oid *twa_sysctl_tree;
struct cam_sim *twa_sim; /* sim for this controller */
struct cam_path *twa_path; /* peripheral, path, tgt, lun
associated with this controller */
};
/*
* Queue primitives
*/
#ifdef TWA_DEBUG
#define TWAQ_INIT(sc, qname) \
do { \
sc->twa_qstats[qname].q_length = 0; \
sc->twa_qstats[qname].q_max = 0; \
} while(0)
#define TWAQ_ADD(sc, qname) \
do { \
struct twa_q_statistics *qs = &(sc)->twa_qstats[qname]; \
\
qs->q_length++; \
if (qs->q_length > qs->q_max) \
qs->q_max = qs->q_length; \
} while(0)
#define TWAQ_REMOVE(sc, qname) (sc)->twa_qstats[qname].q_length--
#else /* TWA_DEBUG */
#define TWAQ_INIT(sc, qname)
#define TWAQ_ADD(sc, qname)
#define TWAQ_REMOVE(sc, qname)
#endif /* TWA_DEBUG */
#define TWAQ_REQUEST_QUEUE(name, index) \
static __inline void twa_initq_ ## name(struct twa_softc *sc) \
{ \
TAILQ_INIT(&sc->twa_ ## name); \
TWAQ_INIT(sc, index); \
} \
static __inline void twa_enqueue_ ## name(struct twa_request *tr) \
{ \
int s; \
\
s = splcam(); \
TAILQ_INSERT_TAIL(&tr->tr_sc->twa_ ## name, tr, tr_link); \
TWAQ_ADD(tr->tr_sc, index); \
splx(s); \
} \
static __inline void twa_requeue_ ## name(struct twa_request *tr) \
{ \
int s; \
\
s = splcam(); \
TAILQ_INSERT_HEAD(&tr->tr_sc->twa_ ## name, tr, tr_link); \
TWAQ_ADD(tr->tr_sc, index); \
splx(s); \
} \
static __inline struct twa_request *twa_dequeue_ ## name(struct twa_softc *sc)\
{ \
struct twa_request *tr; \
int s; \
\
s = splcam(); \
if ((tr = TAILQ_FIRST(&sc->twa_ ## name)) != NULL) { \
TAILQ_REMOVE(&sc->twa_ ## name, tr, tr_link); \
TWAQ_REMOVE(sc, index); \
} \
splx(s); \
return(tr); \
} \
static __inline void twa_remove_ ## name(struct twa_request *tr) \
{ \
int s; \
\
s = splcam(); \
TAILQ_REMOVE(&tr->tr_sc->twa_ ## name, tr, tr_link); \
TWAQ_REMOVE(tr->tr_sc, index); \
splx(s); \
}
TWAQ_REQUEST_QUEUE(free, TWAQ_FREE)
TWAQ_REQUEST_QUEUE(busy, TWAQ_BUSY)
TWAQ_REQUEST_QUEUE(pending, TWAQ_PENDING)
TWAQ_REQUEST_QUEUE(complete, TWAQ_COMPLETE)
#ifdef TWA_DEBUG
extern u_int8_t twa_dbg_level;
extern u_int8_t twa_call_dbg_level;
/* Printf with the bus device in question. */
#define twa_dbg_dprint(dbg_level, sc, fmt, args...) \
do { \
if (dbg_level <= twa_dbg_level) \
device_printf(sc->twa_bus_dev, \
"%s: " fmt "\n", __func__ , ##args);\
} while(0)
#define twa_dbg_dprint_enter(dbg_level, sc) \
do { \
if (dbg_level <= twa_call_dbg_level) \
device_printf(sc->twa_bus_dev, \
"%s: entered.\n", __func__); \
} while(0)
#define twa_dbg_dprint_exit(dbg_level, sc) \
do { \
if (dbg_level <= twa_call_dbg_level) \
device_printf(sc->twa_bus_dev, \
"%s: exiting.\n", __func__); \
} while(0)
#define twa_dbg_print(dbg_level, fmt, args...) \
do { \
if (dbg_level <= twa_dbg_level) \
printf("%s: " fmt "\n", __func__ , ##args);\
} while(0)
#else
#define twa_dbg_dprint(dbg_level, sc, fmt, args...)
#define twa_dbg_dprint_enter(dbg_level, sc)
#define twa_dbg_dprint_exit(dbg_level, sc)
#define twa_dbg_print(dbg_level, fmt, args...)
#endif
#define twa_printf(sc, fmt, args...) \
device_printf(sc->twa_bus_dev, fmt, ##args)

View File

@ -1,792 +0,0 @@
/*-
* Copyright (c) 2003-04 3ware, Inc.
* 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$
*/
/*
* 3ware driver for 9000 series storage controllers.
*
* Author: Vinod Kashyap
*/
#include <dev/twa/twa_includes.h>
#include <cam/cam.h>
#include <cam/cam_ccb.h>
#include <cam/cam_sim.h>
#include <cam/cam_xpt_sim.h>
#include <cam/cam_xpt_periph.h>
#include <cam/cam_debug.h>
#include <cam/cam_periph.h>
#include <cam/scsi/scsi_all.h>
#include <cam/scsi/scsi_message.h>
static int twa_execute_scsi(struct twa_request *tr, union ccb *ccb);
static void twa_action(struct cam_sim *sim, union ccb *ccb);
static void twa_poll(struct cam_sim *sim);
static void twa_async(void *callback_arg, u_int32_t code, struct cam_path *path, void *arg);
static void twa_timeout(void *arg);
static void twa_bus_scan_cb(struct cam_periph *periph, union ccb *ccb);
/*
* Function name: twa_cam_setup
* Description: Attaches the driver to CAM.
*
* Input: sc -- ptr to per ctlr structure
* Output: None
* Return value: 0 -- success
* non-zero-- failure
*/
int
twa_cam_setup(struct twa_softc *sc)
{
struct cam_devq *devq;
struct ccb_setasync csa;
twa_dbg_dprint(3, sc, "sc = %p", sc);
/*
* Create the device queue for our SIM.
*/
devq = cam_simq_alloc(TWA_Q_LENGTH);
if (devq == NULL)
return(ENOMEM);
/*
* Create a SIM entry. Though we can support TWA_Q_LENGTH simultaneous
* requests, we claim to be able to handle only (TWA_Q_LENGTH - 1), so
* that we always have a request packet available to service attention
* interrupts.
*/
twa_dbg_dprint(3, sc, "Calling cam_sim_alloc");
sc->twa_sim = cam_sim_alloc(twa_action, twa_poll, "twa", sc,
device_get_unit(sc->twa_bus_dev),
TWA_Q_LENGTH - 1, 1, devq);
if (sc->twa_sim == NULL) {
cam_simq_free(devq);
return(ENOMEM);
}
/*
* Register the bus.
*/
twa_dbg_dprint(3, sc, "Calling xpt_bus_register");
if (xpt_bus_register(sc->twa_sim, 0) != CAM_SUCCESS) {
cam_sim_free(sc->twa_sim, TRUE);
sc->twa_sim = NULL; /* so twa_cam_detach will not try to free it */
return(ENXIO);
}
twa_dbg_dprint(3, sc, "Calling xpt_create_path");
if (xpt_create_path(&sc->twa_path, NULL,
cam_sim_path(sc->twa_sim),
CAM_TARGET_WILDCARD,
CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
xpt_bus_deregister(cam_sim_path (sc->twa_sim));
cam_sim_free(sc->twa_sim, TRUE); /* passing TRUE will free the devq as well */
return(ENXIO);
}
twa_dbg_dprint(3, sc, "Calling xpt_setup_ccb");
xpt_setup_ccb(&csa.ccb_h, sc->twa_path, 5);
csa.ccb_h.func_code = XPT_SASYNC_CB;
csa.event_enable = AC_FOUND_DEVICE | AC_LOST_DEVICE;
csa.callback = twa_async;
csa.callback_arg = sc;
xpt_action((union ccb *)&csa);
twa_dbg_dprint(3, sc, "Calling twa_request_bus_scan");
/*
* Request a bus scan, so that CAM gets to know of
* the logical units that we control.
*/
twa_request_bus_scan(sc);
twa_dbg_dprint(3, sc, "Exiting");
return(0);
}
/*
* Function name: twa_cam_detach
* Description: Detaches the driver from CAM.
*
* Input: sc -- ptr to per ctlr structure
* Output: None
* Return value: None
*/
void
twa_cam_detach(struct twa_softc *sc)
{
if (sc->twa_path)
xpt_free_path(sc->twa_path);
if (sc->twa_sim) {
xpt_bus_deregister(cam_sim_path(sc->twa_sim));
cam_sim_free(sc->twa_sim, TRUE); /* passing TRUE will free the devq as well */
}
}
/*
* Function name: twa_send_scsi_cmd
* Description: Sends down a scsi cmd to fw.
*
* Input: tr -- ptr to request pkt
* cmd -- opcode of scsi cmd to send
* Output: None
* Return value: 0 -- success
* non-zero-- failure
*/
int
twa_send_scsi_cmd(struct twa_request *tr, int cmd)
{
union ccb ccb;
bzero(&ccb, sizeof(union ccb));
ccb.csio.cdb_io.cdb_bytes[0] = (u_int8_t)cmd;
ccb.csio.cdb_io.cdb_bytes[4] = 128;
ccb.csio.cdb_len = 16;
if ((ccb.csio.data_ptr = malloc(TWA_SECTOR_SIZE, M_DEVBUF, M_NOWAIT))
== NULL)
return(ENOMEM);
bzero(ccb.csio.data_ptr, TWA_SECTOR_SIZE);
ccb.csio.dxfer_len = TWA_SECTOR_SIZE;
ccb.ccb_h.target_id = 0;
ccb.ccb_h.flags |= CAM_DIR_IN;
if (twa_execute_scsi(tr, &ccb))
return(EIO);
return(0);
}
/*
* Function name: twa_execute_scsi
* Description: Build a fw cmd, based on a CAM style ccb, and
* send it down.
*
* Input: tr -- ptr to request pkt
* ccb -- ptr to CAM style ccb
* Output: None
* Return value: 0 -- success
* non-zero-- failure
*/
int
twa_execute_scsi(struct twa_request *tr, union ccb *ccb)
{
struct twa_softc *sc = tr->tr_sc;
struct twa_command_packet *cmdpkt;
struct twa_command_9k *cmd9k;
struct ccb_hdr *ccb_h = &(ccb->ccb_h);
struct ccb_scsiio *csio = &(ccb->csio);
int error;
twa_dbg_dprint(3, sc, "SCSI I/O request 0x%x",
csio->cdb_io.cdb_bytes[0]);
if (ccb_h->target_id >= TWA_MAX_UNITS) {
twa_dbg_dprint(3, sc, "Invalid target. PTL = %x %x %x",
ccb_h->path_id, ccb_h->target_id, ccb_h->target_lun);
ccb_h->status |= CAM_TID_INVALID;
if (tr->tr_cmd_pkt_type & TWA_CMD_PKT_TYPE_EXTERNAL)
xpt_done(ccb);
return(1);
}
if (ccb_h->target_lun != 0) {
twa_dbg_dprint(3, sc, "Invalid lun. PTL = %x %x %x",
ccb_h->path_id, ccb_h->target_id, ccb_h->target_lun);
ccb_h->status |= CAM_LUN_INVALID;
if (tr->tr_cmd_pkt_type & TWA_CMD_PKT_TYPE_EXTERNAL)
xpt_done(ccb);
return(1);
}
if(ccb_h->flags & CAM_CDB_PHYS) {
twa_printf(sc, "Physical CDB address!\n");
ccb_h->status = CAM_REQ_CMP_ERR;
if (tr->tr_cmd_pkt_type & TWA_CMD_PKT_TYPE_EXTERNAL)
xpt_done(ccb);
return(1);
}
/*
* We are going to work on this request. Mark it as enqueued (though
* we don't actually queue it...)
*/
ccb_h->status |= CAM_SIM_QUEUED;
if((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
if(ccb_h->flags & CAM_DIR_IN)
tr->tr_flags |= TWA_CMD_DATA_IN;
else
tr->tr_flags |= TWA_CMD_DATA_OUT;
}
cmdpkt = tr->tr_command;
cmdpkt->cmd_hdr.header_desc.size_header = 128;
cmd9k = &(cmdpkt->command.cmd_pkt_9k);
cmd9k->command.opcode = TWA_OP_EXECUTE_SCSI_COMMAND;
cmd9k->unit = ccb_h->target_id;
cmd9k->request_id = tr->tr_request_id;
cmd9k->status = 0;
cmd9k->sgl_offset = 16; /* offset from end of hdr = max cdb len */
if(ccb_h->flags & CAM_CDB_POINTER)
bcopy(csio->cdb_io.cdb_ptr, cmd9k->cdb, csio->cdb_len);
else
bcopy(csio->cdb_io.cdb_bytes, cmd9k->cdb, csio->cdb_len);
if (!(ccb_h->flags & CAM_DATA_PHYS)) {
/* Virtual data addresses. Need to convert them... */
twa_dbg_dprint(3, sc, "XPT_SCSI_IO: Single virtual address!");
if (!(ccb_h->flags & CAM_SCATTER_VALID)) {
if (csio->dxfer_len > TWA_MAX_IO_SIZE) {
twa_printf(sc, "I/O size %d too big.\n",
csio->dxfer_len);
ccb_h->status = CAM_REQ_TOO_BIG;
if (tr->tr_cmd_pkt_type & TWA_CMD_PKT_TYPE_EXTERNAL)
xpt_done(ccb);
return(1);
}
if ((tr->tr_length = csio->dxfer_len)) {
tr->tr_data = csio->data_ptr;
cmd9k->sgl_entries = 1;
}
} else {
twa_printf(sc, "twa_execute_scsi: XPT_SCSI_IO: Got SGList!\n");
ccb_h->status = CAM_REQ_CMP_ERR;
if (tr->tr_cmd_pkt_type & TWA_CMD_PKT_TYPE_EXTERNAL) {
xpt_done(ccb);
}
return(1);
}
} else {
/* Data addresses are physical. */
twa_printf(sc, "twa_execute_scsi: XPT_SCSI_IO: Physical data addresses!\n");
ccb_h->status = CAM_REQ_CMP_ERR;
if (tr->tr_cmd_pkt_type & TWA_CMD_PKT_TYPE_EXTERNAL) {
ccb_h->status |= CAM_RELEASE_SIMQ;
ccb_h->status &= ~CAM_SIM_QUEUED;
xpt_done(ccb);
}
return(1);
}
tr->tr_cmd_pkt_type |= TWA_CMD_PKT_TYPE_9K;
twa_set_timer(tr);
/* twa_setup_data_dmamap will fill in the SGL, and submit the I/O. */
error = twa_map_request(tr);
return(error);
}
/*
* Function name: twa_action
* Description: Driver entry point for CAM's use.
*
* Input: sim -- sim corresponding to the ctlr
* ccb -- ptr to CAM request
* Output: None
* Return value: None
*/
void
twa_action(struct cam_sim *sim, union ccb *ccb)
{
struct twa_softc *sc = (struct twa_softc *)cam_sim_softc(sim);
struct ccb_hdr *ccb_h = &(ccb->ccb_h);
switch (ccb_h->func_code) {
case XPT_SCSI_IO: /* SCSI I/O */
{
struct twa_request *tr;
if ((sc->twa_state & TWA_STATE_SIMQ_FROZEN) ||
((tr = twa_get_request(sc)) == NULL)) {
twa_dbg_dprint(2, sc, "simq frozen/Cannot get request pkt.");
/*
* Freeze the simq to maintain ccb ordering. The next
* ccb that gets completed will unfreeze the simq.
*/
twa_disallow_new_requests(sc);
ccb_h->status |= CAM_REQUEUE_REQ;
xpt_done(ccb);
break;
}
tr->tr_cmd_pkt_type |= TWA_CMD_PKT_TYPE_EXTERNAL;
tr->tr_private = ccb;
tr->tr_callback = twa_complete_io;
if (twa_execute_scsi(tr, ccb))
twa_release_request(tr);
break;
}
case XPT_ABORT:
twa_dbg_dprint(2, sc, "Abort request");
ccb_h->status = CAM_UA_ABORT;
xpt_done(ccb);
break;
case XPT_RESET_BUS:
twa_printf(sc, "Reset Bus request from CAM...\n");
if (twa_reset(sc)) {
twa_printf(sc, "Reset Bus failed!\n");
ccb_h->status = CAM_REQ_CMP_ERR;
}
else
ccb_h->status = CAM_REQ_CMP;
xpt_done(ccb);
break;
case XPT_SET_TRAN_SETTINGS:
twa_dbg_dprint(3, sc, "XPT_SET_TRAN_SETTINGS");
/*
* This command is not supported, since it's very specific
* to SCSI, and we are doing ATA.
*/
ccb_h->status = CAM_FUNC_NOTAVAIL;
xpt_done(ccb);
break;
case XPT_GET_TRAN_SETTINGS:
{
struct ccb_trans_settings *cts = &ccb->cts;
twa_dbg_dprint(3, sc, "XPT_GET_TRAN_SETTINGS");
cts->valid = (CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID);
cts->flags &= ~(CCB_TRANS_DISC_ENB | CCB_TRANS_TAG_ENB);
ccb_h->status = CAM_REQ_CMP;
xpt_done(ccb);
break;
}
case XPT_CALC_GEOMETRY:
twa_dbg_dprint(3, sc, "XPT_CALC_GEOMETRY request");
cam_calc_geometry(&ccb->ccg, 1/* extended */);
xpt_done(ccb);
break;
case XPT_PATH_INQ: /* Path inquiry -- get twa properties */
{
struct ccb_pathinq *path_inq = &ccb->cpi;
twa_dbg_dprint(3, sc, "XPT_PATH_INQ request");
path_inq->version_num = 1;
path_inq->hba_inquiry = 0;
path_inq->target_sprt = 0;
path_inq->hba_misc = 0;
path_inq->hba_eng_cnt = 0;
path_inq->max_target = TWA_MAX_UNITS;
path_inq->max_lun = 0;
path_inq->unit_number = cam_sim_unit(sim);
path_inq->bus_id = cam_sim_bus(sim);
path_inq->initiator_id = 12;
path_inq->base_transfer_speed = 100000;
strncpy(path_inq->sim_vid, "FreeBSD", SIM_IDLEN);
strncpy(path_inq->hba_vid, "3ware", HBA_IDLEN);
strncpy(path_inq->dev_name, cam_sim_name(sim), DEV_IDLEN);
ccb_h->status = CAM_REQ_CMP;
xpt_done(ccb);
break;
}
default:
twa_dbg_dprint(3, sc, "func_code = %x", ccb_h->func_code);
ccb_h->status = CAM_REQ_INVALID;
xpt_done(ccb);
break;
}
}
/*
* Function name: twa_poll
* Description: Driver entry point called when interrupts are not available.
*
* Input: sim -- sim corresponding to the controller
* Output: None
* Return value: None
*/
void
twa_poll(struct cam_sim *sim)
{
#ifdef TWA_DEBUG
struct twa_softc *sc = (struct twa_softc *)cam_sim_softc(sim);
#endif /* TWA_DEBUG */
twa_dbg_dprint(3, sc, "Entering sc = %p", sc);
twa_interrupt(cam_sim_softc(sim));
twa_dbg_dprint(3, sc, "Exiting sc = %p", sc);
}
/*
* Function name: twa_async
* Description: Driver entry point for CAM to notify driver of special
* events. We don't use this for now.
*
* Input: callback_arg -- ptr to per ctlr structure
* code -- code associated with the event
* path -- cam path
* arg --
* Output: None
* Return value: 0 -- success
* non-zero-- failure
*/
void
twa_async(void *callback_arg, u_int32_t code,
struct cam_path *path, void *arg)
{
#ifdef TWA_DEBUG
struct twa_softc *sc = (struct twa_softc *)callback_arg;
#endif /* TWA_DEBUG */
twa_dbg_dprint(3, sc, "sc = %p, code = %x, path = %p, arg = %p",
sc, code, path, arg);
}
/*
* Function name: twa_timeout
* Description: Driver entry point for being alerted on a request
* timing out.
*
* Input: arg -- ptr to timed out request
* Output: None
* Return value: None
*/
static void
twa_timeout(void *arg)
{
struct twa_request *tr = (struct twa_request *)arg;
struct twa_softc *sc = (struct twa_softc *)(tr->tr_sc);
twa_printf(sc, "Request timed out! tr = %p\n", tr);
twa_reset(sc);
}
/*
* Function name: twa_request_bus_scan
* Description: Requests CAM for a scan of the bus.
*
* Input: sc -- ptr to per ctlr structure
* Output: None
* Return value: None
*/
void
twa_request_bus_scan(struct twa_softc *sc)
{
struct cam_path *path;
union ccb *ccb;
if ((ccb = malloc(sizeof(union ccb), M_TEMP, M_WAITOK)) == NULL)
return;
bzero(ccb, sizeof(union ccb));
if (xpt_create_path(&path, xpt_periph, cam_sim_path(sc->twa_sim),
CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP)
return;
xpt_setup_ccb(&ccb->ccb_h, path, 5);
ccb->ccb_h.func_code = XPT_SCAN_BUS;
ccb->ccb_h.cbfcnp = twa_bus_scan_cb;
ccb->crcn.flags = CAM_FLAG_NONE;
xpt_action(ccb);
}
/*
* Function name: twa_bus_scan_cb
* Description: Callback from CAM on a bus scan request.
*
* Input: periph -- we don't use this
* ccb -- bus scan request ccb that we sent to CAM
* Output: None
* Return value: None
*/
static void
twa_bus_scan_cb(struct cam_periph *periph, union ccb *ccb)
{
twa_dbg_print(3, "ccb = %p\n", ccb);
if (ccb->ccb_h.status != CAM_REQ_CMP)
printf("cam_scan_callback: failure status = %x\n",
ccb->ccb_h.status);
else
twa_dbg_print(3, "success");
xpt_free_path(ccb->ccb_h.path);
free(ccb, M_TEMP);
}
/*
* Function name: twa_scsi_complete
* Description: Called to complete CAM scsi requests.
*
* Input: tr -- ptr to request pkt to be completed
* Output: None
* Return value: None
*/
void
twa_scsi_complete(struct twa_request *tr)
{
struct twa_softc *sc = tr->tr_sc;
struct twa_command_header *cmd_hdr = &(tr->tr_command->cmd_hdr);
struct twa_command_9k *cmd = &(tr->tr_command->command.cmd_pkt_9k);
union ccb *ccb = (union ccb *)(tr->tr_private);
u_int16_t error;
u_int8_t *cdb;
twa_unset_timer(tr);
if (tr->tr_error) {
if (tr->tr_error == EBUSY)
ccb->ccb_h.status |= CAM_REQUEUE_REQ;
else if (tr->tr_error == EFBIG)
ccb->ccb_h.status = CAM_REQ_TOO_BIG;
else
ccb->ccb_h.status = CAM_REQ_CMP_ERR;
} else {
if (cmd->status) {
twa_dbg_dprint(1, sc, "req_id = 0x%x, status = 0x%x",
cmd->request_id,
cmd->status);
error = cmd_hdr->status_block.error;
if ((error == TWA_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) ||
(error == TWA_ERROR_UNIT_OFFLINE)) {
twa_dbg_dprint(3, sc, "Unsupported unit. PTL = %x %x %x",
ccb->ccb_h.path_id,
ccb->ccb_h.target_id,
ccb->ccb_h.target_lun);
ccb->ccb_h.status |= CAM_TID_INVALID;
} else {
twa_dbg_dprint(2, sc, "cmd = %x %x %x %x %x %x %x",
cmd->command.opcode,
cmd->command.reserved,
cmd->unit,
cmd->request_id,
cmd->status,
cmd->sgl_offset,
cmd->sgl_entries);
cdb = (u_int8_t *)(cmd->cdb);
twa_dbg_dprint(2, sc, "cdb = %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",
cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7],
cdb[8], cdb[9], cdb[10], cdb[11], cdb[12], cdb[13], cdb[14], cdb[15]);
/*
* Print the error. Firmware doesn't yet support
* the 'Mode Sense' cmd. Don't print if the cmd
* is 'Mode Sense', and the error is 'Invalid field
* in CDB'.
*/
if (! ((cdb[0] == 0x1A) && (error == 0x10D))) {
u_int8_t *error_str =
&(cmd_hdr->err_desc[strlen(cmd_hdr->err_desc) + 1]);
if (error_str[0] == '\0')
error_str =
twa_find_msg_string(twa_error_table, error);
twa_printf(sc, "SCSI cmd = 0x%x: ERROR: (0x%02X: 0x%04X): %s: %s\n",
cdb[0],
TWA_MESSAGE_SOURCE_CONTROLLER_ERROR,
error,
error_str,
cmd_hdr->err_desc);
}
}
bcopy(cmd_hdr->sense_data, &(ccb->csio.sense_data),
TWA_SENSE_DATA_LENGTH);
ccb->csio.sense_len = TWA_SENSE_DATA_LENGTH;
ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID;
} else
ccb->ccb_h.status = CAM_REQ_CMP;
ccb->csio.scsi_status = cmd->status;
/* If simq is frozen, unfreeze it. */
if (sc->twa_state & TWA_STATE_SIMQ_FROZEN)
twa_allow_new_requests(sc, (void *)ccb);
}
ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
xpt_done(ccb);
}
/*
* Function name: twa_drain_busy_queue
* Description: This function gets called after a controller reset.
* It errors back to CAM, all those requests that were
* pending with the firmware, at the time of the reset.
*
* Input: sc -- ptr to per ctlr structure
* Output: None
* Return value: None
*/
void
twa_drain_busy_queue(struct twa_softc *sc)
{
struct twa_request *tr;
union ccb *ccb;
/* Walk the busy queue. */
while ((tr = twa_dequeue_busy(sc))) {
twa_unmap_request(tr);
if ((tr->tr_cmd_pkt_type & TWA_CMD_PKT_TYPE_INTERNAL) ||
(tr->tr_cmd_pkt_type & TWA_CMD_PKT_TYPE_IOCTL)) {
/*
* It's an internal/ioctl request. The callback/
* originator should do the clean-up (except unmapping).
*/
tr->tr_error = EIO;
if (tr->tr_flags & TWA_CMD_SLEEP_ON_REQUEST) {
tr->tr_flags &= ~TWA_CMD_SLEEP_ON_REQUEST;
wakeup_one(tr);/* let the caller know */
}
else
if (tr->tr_callback)
tr->tr_callback(tr);
} else {
if ((ccb = tr->tr_private)) {
twa_unset_timer(tr);
/* It's a SCSI request. Complete it. */
ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
twa_allow_new_requests(sc, ccb);
ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
xpt_done(ccb);
}
twa_release_request(tr);
}
}
}
/*
* Function name: twa_allow_new_requests
* Description: Sets the appropriate status bits in a ccb such that,
* when the ccb is completed by a call to xpt_done,
* CAM knows that it's ok to unfreeze the flow of new
* requests to this controller, if the flow is frozen.
*
* Input: sc -- ptr to per ctlr structure
* ccb -- ptr to CAM request
* Output: None
* Return value: None
*/
void
twa_allow_new_requests(struct twa_softc *sc, void *ccb)
{
((union ccb *)(ccb))->ccb_h.status |= CAM_RELEASE_SIMQ;
sc->twa_state &= ~TWA_STATE_SIMQ_FROZEN;
}
/*
* Function name: twa_disallow_new_requests
* Description: Calls the appropriate CAM function, so as to freeze
* the flow of new requests from CAM to this controller.
*
* Input: sc -- ptr to per ctlr structure
* Output: None
* Return value: None
*/
void
twa_disallow_new_requests(struct twa_softc *sc)
{
xpt_freeze_simq(sc->twa_sim, 1);
sc->twa_state |= TWA_STATE_SIMQ_FROZEN;
}
/*
* Function name: twa_set_timer
* Description: Set a timer to time a given request.
*
* Input: tr -- ptr to request pkt
* Output: None
* Return value: None
*/
void
twa_set_timer(struct twa_request *tr)
{
union ccb *ccb = (union ccb *)(tr->tr_private);
/* Set the timer only if external (CAM) request. */
if (ccb) {
tr->tr_flags |= TWA_CMD_TIMER_SET;
ccb->ccb_h.timeout_ch = timeout(twa_timeout, tr,
(ccb->ccb_h.timeout * hz) / 1000);
}
}
/*
* Function name: twa_unset_timer
* Description: Unset a previously set timer.
*
* Input: tr -- ptr to request pkt
* Output: None
* Return value: None
*/
void
twa_unset_timer(struct twa_request *tr)
{
union ccb *ccb = (union ccb *)(tr->tr_private);
if (tr->tr_flags & TWA_CMD_TIMER_SET) {
untimeout(twa_timeout, tr, ccb->ccb_h.timeout_ch);
tr->tr_flags &= ~TWA_CMD_TIMER_SET;
}
}

View File

@ -1,79 +0,0 @@
/*-
* Copyright (c) 2003-04 3ware, Inc.
* 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$
*/
/*
* 3ware driver for 9000 series storage controllers.
*
* Author: Vinod Kashyap
*/
/* Global data structures */
extern char twa_fw_img[];
extern int twa_fw_img_size;
extern struct twa_message twa_aen_table[];
extern char *twa_aen_severity_table[];
extern struct twa_message twa_error_table[];
/* Functions in twa.c */
extern int twa_setup(struct twa_softc *sc); /* do early driver/controller setup */
extern int twa_deinit_ctlr(struct twa_softc *sc); /* stop controller */
extern void twa_interrupt(struct twa_softc *sc); /* ISR */
extern int twa_ioctl(struct twa_softc *sc, int cmd, void *addr);/* handle user request */
extern void twa_enable_interrupts(struct twa_softc *sc); /* enable controller interrupts */
extern void twa_disable_interrupts(struct twa_softc *sc); /* disable controller interrupts */
extern void twa_complete_io(struct twa_request *tr); /* I/O completion callback */
extern int twa_reset(struct twa_softc *sc); /* (soft) reset controller */
extern int twa_submit_io(struct twa_request *tr); /* wrapper to twa_start */
extern int twa_start(struct twa_request *tr); /* submit command to controller */
extern char *twa_find_msg_string(struct twa_message *table, u_int16_t code);/* lookup a msg */
extern struct twa_request *twa_get_request(struct twa_softc *sc);/* get a req pkt from free pool */
extern void twa_release_request(struct twa_request *tr); /* put a req pkt back into free pool */
extern void twa_describe_controller(struct twa_softc *sc); /* describe controller info */
extern void twa_print_controller(struct twa_softc *sc); /* print controller state */
/* Functions in twa_freebsd.c */
extern void twa_write_pci_config(struct twa_softc *sc, u_int32_t value, int size);/* write to pci config space */
extern int twa_alloc_req_pkts(struct twa_softc *sc, int num_reqs); /* alloc req & cmd pkts */
extern int twa_map_request(struct twa_request *tr); /* copy cmd pkt & data to DMA'able memory */
extern void twa_unmap_request(struct twa_request *tr); /* undo mapping */
/* Functions in twa_cam.c */
extern void twa_request_bus_scan(struct twa_softc *sc); /* request CAM for a bus scan */
extern int twa_send_scsi_cmd(struct twa_request *tr, int cmd);/* send down a SCSI cmd */
extern void twa_scsi_complete(struct twa_request *tr); /* complete a SCSI cmd by calling CAM */
extern void twa_drain_busy_queue(struct twa_softc *sc); /* drain busy queue (during reset) */
extern int twa_cam_setup(struct twa_softc *sc); /* attach to CAM */
extern void twa_cam_detach(struct twa_softc *sc); /* detach from CAM */
extern void twa_allow_new_requests(struct twa_softc *sc, void *ccb);/* unfreeze ccb flow from CAM */
extern void twa_disallow_new_requests(struct twa_softc *sc);/* freeze ccb flow from CAM */
extern void twa_set_timer(struct twa_request *tr); /* Set a timer to time a given request */
extern void twa_unset_timer(struct twa_request *tr);/* Unset a previously set timer */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,321 +0,0 @@
/*-
* Copyright (c) 2003-04 3ware, Inc.
* 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$
*/
/*
* 3ware driver for 9000 series storage controllers.
*
* Author: Vinod Kashyap
*/
#include <dev/twa/twa_includes.h>
/* AEN messages. */
struct twa_message twa_aen_table[] = {
{0x0000, "AEN queue empty"},
{0x0001, "Controller reset occurred"},
{0x0002, "Degraded unit detected"},
{0x0003, "Controller error occured"},
{0x0004, "Background rebuild failed"},
{0x0005, "Background rebuild done"},
{0x0006, "Incomplete unit detected"},
{0x0007, "Background initialize done"},
{0x0008, "Unclean shutdown detected"},
{0x0009, "Drive timeout detected"},
{0x000A, "Drive error detected"},
{0x000B, "Rebuild started"},
{0x000C, "Background initialize started"},
{0x000D, "Entire logical unit was deleted"},
{0x000E, "Background initialize failed"},
{0x000F, "SMART attribute exceeded threshold"},
{0x0010, "Power supply reported AC under range"},
{0x0011, "Power supply reported DC out of range"},
{0x0012, "Power supply reported a malfunction"},
{0x0013, "Power supply predicted malfunction"},
{0x0014, "Battery charge is below threshold"},
{0x0015, "Fan speed is below threshold"},
{0x0016, "Temperature sensor is above threshold"},
{0x0017, "Power supply was removed"},
{0x0018, "Power supply was inserted"},
{0x0019, "Drive was removed from a bay"},
{0x001A, "Drive was inserted into a bay"},
{0x001B, "Drive bay cover door was opened"},
{0x001C, "Drive bay cover door was closed"},
{0x001D, "Product case was opened"},
{0x0020, "Prepare for shutdown (power-off)"},
{0x0021, "Downgrade UDMA mode to lower speed"},
{0x0022, "Upgrade UDMA mode to higher speed"},
{0x0023, "Sector repair completed"},
{0x0024, "Sbuf memory test failed"},
{0x0025, "Error flushing cached write data to disk"},
{0x0026, "Drive reported data ECC error"},
{0x0027, "DCB has checksum error"},
{0x0028, "DCB version is unsupported"},
{0x0029, "Background verify started"},
{0x002A, "Background verify failed"},
{0x002B, "Background verify done"},
{0x002C, "Bad sector overwritten during rebuild"},
{0x002E, "Replace failed because replacement drive too small"},
{0x002F, "Verify failed because array was never initialized"},
{0x0030, "Unsupported ATA drive"},
{0x0031, "Synchronize host/controller time"},
{0x0032, "Spare capacity is inadequate for some units"},
{0x0033, "Background migration started"},
{0x0034, "Background migration failed"},
{0x0035, "Background migration done"},
{0x0036, "Verify detected and fixed data/parity mismatch"},
{0x0037, "SO-DIMM incompatible"},
{0x0038, "SO-DIMM not detected"},
{0x0039, "Corrected Sbuf ECC error"},
{0x003A, "Drive power on reset detected"},
{0x003B, "Background rebuild paused"},
{0x003C, "Background initialize paused"},
{0x003D, "Background verify paused"},
{0x003E, "Background migration paused"},
{0x003F, "Corrupt flash file system detected"},
{0x0040, "Flash file system repaired"},
{0x0041, "Unit number assignments were lost"},
{0x0042, "Error during read of primary DCB"},
{0x0043, "Latent error found in backup DCB"},
{0x0044, "Voltage is within normal range"},
{0x0045, "Voltage is in low warning range"},
{0x0046, "Voltage is in high warning range"},
{0x0047, "Voltage is below operating range"},
{0x0048, "Voltage is above operating range"},
{0x0049, "Temperature is within normal range"},
{0x004A, "Temperature is in low warning range"},
{0x004B, "Temperature is high warning range"},
{0x004C, "Temperature is below operating range"},
{0x004D, "Temperature is above operating range"},
{0x004E, "Low current test started"},
{0x0050, "Low current test stopped"},
{0x0051, "High current test started"},
{0x0052, "High current test stopped"},
{0x0053, "Charge termination voltage is at high level"},
{0x0054, "Charge termination voltage is at high level"},
{0x0055, "Charge started"},
{0x0056, "Charge stopped"},
{0x0057, "Charge is in fault condition"},
{0x0058, "Capacity is below warning level"},
{0x0059, "Capacity is below error level"},
{0x005A, "Battery is present"},
{0x005B, "Battery is not present"},
{0x005C, "High current test is in warning level"},
{0x005D, "High current test is in fault level"},
{0x0060, "Bad cache meta data checksum"},
{0x0061, "Bad cache meta data signature"},
{0x0062, "Cache meta data restore failed"},
{0x0063, "Cache meta data was lost"},
{0x0064, "Cache write data sync failed"},
{0x0065, "Not able to sync cache write data"},
{0x00FC, "Recovered/finished array membership update"},
{0x00FD, "Handler lockup"},
{0x00FE, "Retrying PCI transfer"},
{0x00FF, "AEN queue is full"},
{0xFFFFFFFF, ""}
};
/* AEN severity table. */
char *twa_aen_severity_table[] = {
"None",
"ERROR",
"WARNING",
"INFO",
"DEBUG",
""
};
/* Error messages. */
struct twa_message twa_error_table[] = {
{0x0100, "SGL entry contains zero data"},
{0x0101, "Invalid command opcode"},
{0x0102, "SGL entry has unaligned address"},
{0x0103, "SGL size does not match command"},
{0x0104, "SGL entry has illegal length"},
{0x0105, "Command packet is not aligned"},
{0x0106, "Invalid request ID"},
{0x0107, "Duplicate request ID"},
{0x0108, "ID not locked"},
{0x0109, "LBA out of range"},
{0x010A, "Logical unit not supported"},
{0x010B, "Parameter table does not exist"},
{0x010C, "Parameter index does not exist"},
{0x010D, "Invalid field in CDB"},
{0x010E, "Specified port has invalid drive"},
{0x010F, "Parameter item size mismatch"},
{0x0110, "Failed memory allocation"},
{0x0111, "Memory request too large"},
{0x0112, "Out of memory segments"},
{0x0113, "Invalid address to deallocate"},
{0x0114, "Out of memory"},
{0x0115, "Out of heap"},
{0x0120, "Double degrade"},
{0x0121, "Drive not degraded"},
{0x0122, "Reconstruct error"},
{0x0123, "Replace not accepted"},
{0x0124, "Drive capacity too small"},
{0x0125, "Sector count not allowed"},
{0x0126, "No spares left"},
{0x0127, "Reconstruct error"},
{0x0128, "Unit is offline"},
{0x0129, "Cannot update status to DCB"},
{0x012A, "Dchnl cannot be split"},
{0x012B, "Dchnl cannot be joined"},
{0x012C, "No migration recovery"},
{0x0130, "Invalid stripe handle"},
{0x0131, "Handle that was not locked"},
{0x0132, "Handle that was not empty"},
{0x0133, "Handle has different owner"},
{0x0140, "IPR has parent"},
{0x0150, "Illegal Pbuf address alignment"},
{0x0151, "Illegal Pbuf transfer length"},
{0x0152, "Illegal Sbuf address alignment"},
{0x0153, "Illegal Sbuf transfer length"},
{0x0160, "Command packet too large"},
{0x0161, "SGL exceeds maximum length"},
{0x0162, "SGL has too many entries"},
{0x0170, "Insufficient resources for rebuilder"},
{0x0171, "Verify error (data != parity)"},
{0x0180, "Requested segment not in directory of this DCB"},
{0x0181, "DCB segment has unsupported version"},
{0x0182, "DCB segment has checksum error"},
{0x0183, "DCB support (settings) segment invalid"},
{0x0184, "DCB UDB (unit descriptor block) segment invalid"},
{0x0185, "DCB GUID (globally unique identifier) segment invalid"},
{0x01A0, "Could not clear Sbuf"},
{0x01C0, "Flash identify failed"},
{0x01C1, "Flash out of bounds"},
{0x01C2, "Flash verify error"},
{0x01C3, "Flash file object not found"},
{0x01C4, "Flash file already present"},
{0x01C5, "Flash file system full"},
{0x01C6, "Flash file not present"},
{0x01C7, "Flash file size error"},
{0x01C8, "Bad flash file checksum"},
{0x01CA, "Corrupt flash file system detected"},
{0x01CB, "Flash file has no component directory"},
{0x01CC, "Flash file component not found"},
{0x01CD, "Flash Write cycle Failed"},
{0x01CE, "Flash Erase cycle Failed"},
{0x01D0, "Invalid field in parameter list"},
{0x01D1, "Parameter list length error"},
{0x01D2, "Parameter item is not changeable"},
{0x01D3, "Parameter item is not saveable"},
{0x0200, "UDMA CRC error"},
{0x0201, "Internal CRC error"},
{0x0202, "Data ECC error"},
{0x0203, "ADP level 1 error"},
{0x0204, "Port timeout"},
{0x0205, "Drive power on reset"},
{0x0206, "ADP level 2 error"},
{0x0207, "Soft reset failed"},
{0x0208, "Drive not ready"},
{0x0209, "Unclassified port error"},
{0x020A, "Drive aborted command"},
{0x0210, "Internal CRC error"},
{0x0211, "PCI abort error"},
{0x0212, "PCI parity error"},
{0x0213, "Port handler error"},
{0x0214, "Token interrupt count error"},
{0x0215, "Timeout waiting for PCI transfer"},
{0x0216, "Corrected buffer ECC"},
{0x0217, "Uncorrected buffer ECC"},
{0x0230, "Unsupported command during flash recovery"},
{0x0231, "Next image buffer expected"},
{0x0232, "Binary image architecture incompatible"},
{0x0233, "Binary image has no signature"},
{0x0234, "Binary image has bad checksum"},
{0x0235, "Binary image overflowed buffer"},
{0x0240, "I2C device not found"},
{0x0241, "I2C transaction aborted"},
{0x0242, "SO-DIMM parameter(s) incompatible using defaults"},
{0x0243, "SO-DIMM unsupported"},
{0x0244, "I2C clock is held low - Transfer aborted"},
{0x0245, "I2C data is held low - Transfer aborted"},
{0x0246, "I2C slave device NACKed the transfer"},
{0x0247, "I2C buffer in-sufficient"},
{0x0248, "SPI transfer status error"},
{0x0249, "SPI transfer timeout error"},
{0x0250, "Invalid unit descriptor size"},
{0x0251, "Unit descriptor size exceeds data buffer"},
{0x0252, "Invalid value in unit descriptor"},
{0x0253, "Inadequate disk space to support descriptor"},
{0x0254, "Unable to create data channel for this unit descriptor"},
{0x0255, "CreateUnit descriptor specifies a drive already in use"},
{0x0256, "Unable to write configuration to all disks during CreateUnit"},
{0x0257, "CreateUnit/MigrateUnit does not support this descriptor version"},
{0x0258, "Invalid subunit for RAID 0 or 5 in CreateUnit/MigrateUnit"},
{0x0259, "Too many descriptors in CreateUnit/MigrateUnit"},
{0x025A, "Invalid configuration specified in unit descriptor"},
{0x025B, "Invalid LBA offset specified in unit descriptor"},
{0x025C, "Invalid stripelet size specified in unit descriptor"},
{0x025D, "JBOD unit is not allowed"},
{0x0260, "SMART attribute exceeded threshold"},
{0x0270, "Unit is not in NORMAL state"},
{0x0271, "Invalid drive members"},
{0x0272, "Converted unit is not supported"},
{0x0300, "Internal errorcode (BBU base) - should not occur"},
{0x0301, "Invalid BBU state change request"},
{0x0302, "The BBU resource needed is in use ; retry command after a delay"},
{0x0303, "Command requires a battery pack to be present and enabled"},
{0x0310, "BBU command packet error"},
{0x0311, "BBU command not implemented"},
{0x0312, "BBU command buffer underflow"},
{0x0313, "BBU command buffer overflow"},
{0x0314, "BBU command incomplete"},
{0x0315, "BBU command checksum error"},
{0x0316, "BBU command timeout"},
{0x0320, "BBU parameter not defined"},
{0x0321, "BBU parameter size mismatch"},
{0x0322, "Cannot write a read-only BBU parameter"},
{0x0323, "BBU firmware version string not found"},
{0x0324, "BBU operating state not available"},
{0x0325, "BBU not present"},
{0x0326, "BBU not ready"},
{0x0327, "BBU S1 not compatible with HBA"},
{0x0328, "BBU S0 not compatible with HBA"},
{0x0329, "BBU not compatible with HBA"},
{0x032A, "BBU not in S0"},
{0x032B, "BBU not in S1"},
{0x032C, "Timeout on BBU power fail interrupt"},
{0x032D, "BBU command checksum error"},
{0x0330, "Log updates not allowed"},
{0x0331, "Logs are invalid"},
{0x0332, "Logs not found"},
{0xFFFFFFFF, ""}
};
#ifdef TWA_DEBUG
/*
* Save the debug levels in global variables, so that
* their values can be changed from the debugger.
*/
u_int8_t twa_dbg_level = TWA_DEBUG;
u_int8_t twa_call_dbg_level = TWA_DEBUG;
#endif /* TWA_DEBUG */

View File

@ -1,125 +0,0 @@
/*-
* Copyright (c) 2003-04 3ware, Inc.
* 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$
*/
/*
* 3ware driver for 9000 series storage controllers.
*
* Author: Vinod Kashyap
*/
#define TWA_AEN_NOT_RETRIEVED 0x1
#define TWA_AEN_RETRIEVED 0x2
#define TWA_ERROR_AEN_NO_EVENTS 0x1003 /* No more events */
#define TWA_ERROR_AEN_OVERFLOW 0x1004 /* AEN clobber occurred */
#define TWA_ERROR_IOCTL_LOCK_NOT_HELD 0x1001 /* Not locked */
#define TWA_ERROR_IOCTL_LOCK_ALREADY_HELD 0x1002 /* Already locked */
#pragma pack(1)
struct twa_scan_bus_packet {
u_int32_t unit;
} __attribute__ ((packed));
struct twa_event_packet {
u_int32_t sequence_id;
u_int32_t time_stamp_sec;
u_int16_t aen_code;
u_int8_t severity;
u_int8_t retrieved;
u_int8_t repeat_count;
u_int8_t parameter_len;
u_int8_t parameter_data[98];
} __attribute__ ((packed));
struct twa_lock_packet {
u_int32_t timeout_msec;
u_int32_t time_remaining_msec;
u_int32_t force_flag;
} __attribute__ ((packed));
struct twa_compatibility_packet {
uint8_t driver_version[32];/* driver version */
uint16_t working_srl; /* driver & firmware negotiated srl */
uint16_t working_branch; /* branch # of the firmware that the driver is compatible with */
uint16_t working_build; /* build # of the firmware that the driver is compatible with */
} __attribute__ ((packed));
struct twa_driver_packet {
u_int32_t control_code;
u_int32_t status;
u_int32_t unique_id;
u_int32_t sequence_id;
u_int32_t os_status;
u_int32_t buffer_length;
} __attribute__ ((packed));
struct twa_ioctl_9k {
struct twa_driver_packet twa_drvr_pkt;
void *pdata; /* points to data_buf */
int8_t padding[488 - sizeof(void *)];
struct twa_command_packet twa_cmd_pkt;
int8_t data_buf[1];
} __attribute__ ((packed));
/*
* We need the structure below to ensure that the first byte of
* data_buf is not overwritten by the kernel, after we return
* from the ioctl call. Note that twa_cmd_pkt has been reduced
* to an array of 1024 bytes even though it's actually 2048 bytes
* in size. This is because, we don't expect requests from user
* land requiring 2048 (273 sg elements) byte cmd pkts.
*/
typedef struct twa_ioctl_no_data_buf {
struct twa_driver_packet twa_drvr_pkt;
void *pdata; /* points to data_buf */
int8_t padding[488 - sizeof(void *)];
struct twa_command_packet twa_cmd_pkt;
} __attribute__ ((packed)) TWA_IOCTL_NO_DATA_BUF;
#pragma pack()
#define TWA_IOCTL_SCAN_BUS _IOW ('T', 200, u_int32_t)
#define TWA_IOCTL_FIRMWARE_PASS_THROUGH _IOWR('T', 202, TWA_IOCTL_NO_DATA_BUF)
#define TWA_IOCTL_GET_FIRST_EVENT _IOWR('T', 203, TWA_IOCTL_NO_DATA_BUF)
#define TWA_IOCTL_GET_LAST_EVENT _IOWR('T', 204, TWA_IOCTL_NO_DATA_BUF)
#define TWA_IOCTL_GET_NEXT_EVENT _IOWR('T', 205, TWA_IOCTL_NO_DATA_BUF)
#define TWA_IOCTL_GET_PREVIOUS_EVENT _IOWR('T', 206, TWA_IOCTL_NO_DATA_BUF)
#define TWA_IOCTL_GET_LOCK _IOWR('T', 207, TWA_IOCTL_NO_DATA_BUF)
#define TWA_IOCTL_RELEASE_LOCK _IOWR('T', 208, TWA_IOCTL_NO_DATA_BUF)
#define TWA_IOCTL_GET_COMPATIBILITY_INFO _IOWR('T', 209, TWA_IOCTL_NO_DATA_BUF)

View File

@ -1,464 +0,0 @@
/*-
* Copyright (c) 2003-04 3ware, Inc.
* 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$
*/
/*
* 3ware driver for 9000 series storage controllers.
*
* Author: Vinod Kashyap
*/
/*
* The following macro has no business being in twa_reg.h. It should probably
* be defined in twa_includes.h, before the #include twa_reg.h.... But that
* causes the API to run into build errors. Will leave it here for now...
*/
#define TWA_64BIT_ADDRESSES ((sizeof(bus_addr_t) == 8) ? 1 : 0)
/* Register offsets from base address. */
#define TWA_CONTROL_REGISTER_OFFSET 0x0
#define TWA_STATUS_REGISTER_OFFSET 0x4
#define TWA_COMMAND_QUEUE_OFFSET 0x8
#define TWA_RESPONSE_QUEUE_OFFSET 0xC
#define TWA_COMMAND_QUEUE_OFFSET_LOW 0x20
#define TWA_COMMAND_QUEUE_OFFSET_HIGH 0x24
/* Functions to read from, and write to registers */
#define TWA_WRITE_CONTROL_REGISTER(sc, val) \
TWA_WRITE_REGISTER(sc, TWA_CONTROL_REGISTER_OFFSET, val)
#define TWA_READ_STATUS_REGISTER(sc) \
TWA_READ_REGISTER(sc, TWA_STATUS_REGISTER_OFFSET)
#define TWA_WRITE_COMMAND_QUEUE(sc, val) \
do { \
if (TWA_64BIT_ADDRESSES) { \
/* First write the low 4 bytes, then the high 4. */ \
TWA_WRITE_REGISTER(sc, TWA_COMMAND_QUEUE_OFFSET_LOW, \
(u_int32_t)(val)); \
TWA_WRITE_REGISTER(sc, TWA_COMMAND_QUEUE_OFFSET_HIGH,\
(u_int32_t)(((u_int64_t)val)>>32)); \
} else \
TWA_WRITE_REGISTER(sc, TWA_COMMAND_QUEUE_OFFSET,\
(u_int32_t)(val)); \
} while (0)
#define TWA_READ_RESPONSE_QUEUE(sc) \
(union twa_response_queue)TWA_READ_REGISTER(sc, TWA_RESPONSE_QUEUE_OFFSET)
/* Control register bit definitions. */
#define TWA_CONTROL_CLEAR_SBUF_WRITE_ERROR 0x00000008
#define TWA_CONTROL_ISSUE_HOST_INTERRUPT 0x00000020
#define TWA_CONTROL_DISABLE_INTERRUPTS 0x00000040
#define TWA_CONTROL_ENABLE_INTERRUPTS 0x00000080
#define TWA_CONTROL_ISSUE_SOFT_RESET 0x00000100
#define TWA_CONTROL_UNMASK_RESPONSE_INTERRUPT 0x00004000
#define TWA_CONTROL_UNMASK_COMMAND_INTERRUPT 0x00008000
#define TWA_CONTROL_MASK_RESPONSE_INTERRUPT 0x00010000
#define TWA_CONTROL_MASK_COMMAND_INTERRUPT 0x00020000
#define TWA_CONTROL_CLEAR_ATTENTION_INTERRUPT 0x00040000
#define TWA_CONTROL_CLEAR_HOST_INTERRUPT 0x00080000
#define TWA_CONTROL_CLEAR_PCI_ABORT 0x00100000
#define TWA_CONTROL_CLEAR_QUEUE_ERROR 0x00400000
#define TWA_CONTROL_CLEAR_PARITY_ERROR 0x00800000
#define TWA_SOFT_RESET(sc) \
TWA_WRITE_CONTROL_REGISTER(sc, \
TWA_CONTROL_ISSUE_SOFT_RESET | \
TWA_CONTROL_CLEAR_HOST_INTERRUPT | \
TWA_CONTROL_CLEAR_ATTENTION_INTERRUPT | \
TWA_CONTROL_MASK_COMMAND_INTERRUPT | \
TWA_CONTROL_MASK_RESPONSE_INTERRUPT | \
TWA_CONTROL_DISABLE_INTERRUPTS)
/* Status register bit definitions. */
#define TWA_STATUS_ROM_BIOS_IN_SBUF 0x00000002
#define TWA_STATUS_SBUF_WRITE_ERROR 0x00000008
#define TWA_STATUS_COMMAND_QUEUE_EMPTY 0x00001000
#define TWA_STATUS_MICROCONTROLLER_READY 0x00002000
#define TWA_STATUS_RESPONSE_QUEUE_EMPTY 0x00004000
#define TWA_STATUS_COMMAND_QUEUE_FULL 0x00008000
#define TWA_STATUS_RESPONSE_INTERRUPT 0x00010000
#define TWA_STATUS_COMMAND_INTERRUPT 0x00020000
#define TWA_STATUS_ATTENTION_INTERRUPT 0x00040000
#define TWA_STATUS_HOST_INTERRUPT 0x00080000
#define TWA_STATUS_PCI_ABORT_INTERRUPT 0x00100000
#define TWA_STATUS_MICROCONTROLLER_ERROR 0x00200000
#define TWA_STATUS_QUEUE_ERROR_INTERRUPT 0x00400000
#define TWA_STATUS_PCI_PARITY_ERROR_INTERRUPT 0x00800000
#define TWA_STATUS_MINOR_VERSION_MASK 0x0F000000
#define TWA_STATUS_MAJOR_VERSION_MASK 0xF0000000
#define TWA_STATUS_EXPECTED_BITS 0x00002000
#define TWA_STATUS_UNEXPECTED_BITS 0x00F00000
/* For use with the %b printf format. */
#define TWA_STATUS_BITS_DESCRIPTION \
"\20\15CMD_Q_EMPTY\16MC_RDY\17RESP_Q_EMPTY\20CMD_Q_FULL\21RESP_INTR\22CMD_INTR\23ATTN_INTR\24HOST_INTR\25PCI_ABRT\26MC_ERR\27Q_ERR\30PCI_PERR\n"
/* Detect inconsistencies in the status register. */
#define TWA_STATUS_ERRORS(x) \
((x & TWA_STATUS_UNEXPECTED_BITS) && \
(x & TWA_STATUS_MICROCONTROLLER_READY))
/* PCI related defines. */
#define TWA_IO_CONFIG_REG 0x10
#define TWA_DEVICE_NAME "3ware 9000 series Storage Controller"
#define TWA_VENDOR_ID 0x13C1
#define TWA_DEVICE_ID_9K 0x1002
#define TWA_PCI_CONFIG_CLEAR_PARITY_ERROR 0xc100
#define TWA_PCI_CONFIG_CLEAR_PCI_ABORT 0x2000
/* Command packet opcodes. */
#define TWA_OP_NOP 0x00
#define TWA_OP_INIT_CONNECTION 0x01
#define TWA_OP_READ 0x02
#define TWA_OP_WRITE 0x03
#define TWA_OP_READVERIFY 0x04
#define TWA_OP_VERIFY 0x05
#define TWA_OP_ZEROUNIT 0x08
#define TWA_OP_REPLACEUNIT 0x09
#define TWA_OP_HOTSWAP 0x0A
#define TWA_OP_SELFTESTS 0x0B
#define TWA_OP_SYNC_PARAM 0x0C
#define TWA_OP_REORDER_UNITS 0x0D
#define TWA_OP_EXECUTE_SCSI_COMMAND 0x10
#define TWA_OP_ATA_PASSTHROUGH 0x11
#define TWA_OP_GET_PARAM 0x12
#define TWA_OP_SET_PARAM 0x13
#define TWA_OP_CREATEUNIT 0x14
#define TWA_OP_DELETEUNIT 0x15
#define TWA_OP_DOWNLOAD_FIRMWARE 0x16
#define TWA_OP_REBUILDUNIT 0x17
#define TWA_OP_POWER_MANAGEMENT 0x18
#define TWA_OP_REMOTE_PRINT 0x1B
#define TWA_OP_RESET_FIRMWARE 0x1C
#define TWA_OP_DEBUG 0x1D
#define TWA_OP_DIAGNOSTICS 0x1F
/* Misc defines. */
#define TWA_BUNDLED_FW_VERSION_STRING "2.04.00.005"
#define TWA_ALIGNMENT 0x4
#define TWA_MAX_UNITS 16
#define TWA_INIT_MESSAGE_CREDITS 0x100
#define TWA_SHUTDOWN_MESSAGE_CREDITS 0x001
#define TWA_64BIT_SG_ADDRESSES 0x00000001
#define TWA_EXTENDED_INIT_CONNECT 0x00000002
#define TWA_BASE_MODE 1
#define TWA_BASE_FW_SRL 23
#define TWA_BASE_FW_BRANCH 0
#define TWA_BASE_FW_BUILD 1
#define TWA_CURRENT_FW_SRL 27
#define TWA_CURRENT_FW_BRANCH 2
#define TWA_CURRENT_FW_BUILD 6
#define TWA_9000_ARCH_ID 0x5 /* 9000 series controllers */
#define TWA_CTLR_FW_SAME_OR_NEWER 0x00000001
#define TWA_CTLR_FW_COMPATIBLE 0x00000002
#define TWA_BUNDLED_FW_SAFE_TO_FLASH 0x00000004
#define TWA_CTLR_FW_RECOMMENDS_FLASH 0x00000008
#define NUM_FW_IMAGE_CHUNKS 5
#define TWA_MAX_IO_SIZE 0x20000 /* 128K */
#define TWA_MAX_SG_ELEMENTS (TWA_64BIT_ADDRESSES ? 70 : 105)
#define TWA_MAX_ATA_SG_ELEMENTS 60
#define TWA_Q_LENGTH TWA_INIT_MESSAGE_CREDITS
#define TWA_MAX_RESET_TRIES 3
#define TWA_SECTOR_SIZE 0x200 /* generic I/O bufffer */
#define TWA_SENSE_DATA_LENGTH 18
#define TWA_ERROR_LOGICAL_UNIT_NOT_SUPPORTED 0x010a
#define TWA_ERROR_UNIT_OFFLINE 0x0128
#define TWA_ERROR_MORE_DATA 0x0231
#pragma pack(1)
/* Scatter/Gather list entry. */
struct twa_sg {
bus_addr_t address;
u_int32_t length;
} __attribute__ ((packed));
/* 7000 structures. */
struct twa_command_init_connect {
u_int8_t opcode:5; /* TWA_OP_INITCONNECTION */
u_int8_t res1:3;
u_int8_t size;
u_int8_t request_id;
u_int8_t res2;
u_int8_t status;
u_int8_t flags;
u_int16_t message_credits;
u_int32_t features;
u_int16_t fw_srl;
u_int16_t fw_arch_id;
u_int16_t fw_branch;
u_int16_t fw_build;
u_int32_t result;
} __attribute__ ((packed));
struct twa_command_download_firmware {
u_int8_t opcode:5; /* TWA_DOWNLOAD_FIRMWARE */
u_int8_t sgl_offset:3;
u_int8_t size;
u_int8_t request_id;
u_int8_t unit;
u_int8_t status;
u_int8_t flags;
u_int16_t param;
struct twa_sg sgl[TWA_MAX_SG_ELEMENTS];
} __attribute__ ((packed));
struct twa_command_reset_firmware {
u_int8_t opcode:5; /* TWA_OP_RESET_FIRMWARE */
u_int8_t res1:3;
u_int8_t size;
u_int8_t request_id;
u_int8_t unit;
u_int8_t status;
u_int8_t flags;
u_int8_t res2;
u_int8_t param;
} __attribute__ ((packed));
struct twa_command_io {
u_int8_t opcode:5; /* TWA_OP_READ/TWA_OP_WRITE */
u_int8_t sgl_offset:3;
u_int8_t size;
u_int8_t request_id;
u_int8_t unit:4;
u_int8_t host_id:4;
u_int8_t status;
u_int8_t flags;
u_int16_t block_count;
u_int32_t lba;
struct twa_sg sgl[TWA_MAX_SG_ELEMENTS];
} __attribute__ ((packed));
struct twa_command_hotswap {
u_int8_t opcode:5; /* TWA_OP_HOTSWAP */
u_int8_t res1:3;
u_int8_t size;
u_int8_t request_id;
u_int8_t unit:4;
u_int8_t host_id:4;
u_int8_t status;
u_int8_t flags;
u_int8_t action;
#define TWA_OP_HOTSWAP_REMOVE 0x00 /* remove assumed-degraded unit */
#define TWA_OP_HOTSWAP_ADD_CBOD 0x01 /* add CBOD to empty port */
#define TWA_OP_HOTSWAP_ADD_SPARE 0x02 /* add spare to empty port */
u_int8_t aport;
} __attribute__ ((packed));
struct twa_command_param {
u_int8_t opcode:5; /* TWA_OP_GETPARAM, TWA_OP_SETPARAM */
u_int8_t sgl_offset:3;
u_int8_t size;
u_int8_t request_id;
u_int8_t unit:4;
u_int8_t host_id:4;
u_int8_t status;
u_int8_t flags;
u_int16_t param_count;
struct twa_sg sgl[TWA_MAX_SG_ELEMENTS];
} __attribute__ ((packed));
struct twa_command_rebuildunit {
u_int8_t opcode:5; /* TWA_OP_REBUILDUNIT */
u_int8_t res1:3;
u_int8_t size;
u_int8_t request_id;
u_int8_t src_unit:4;
u_int8_t host_id:4;
u_int8_t status;
u_int8_t flags;
u_int8_t action:7;
#define TWA_OP_REBUILDUNIT_NOP 0
#define TWA_OP_REBUILDUNIT_STOP 2 /* stop all rebuilds */
#define TWA_OP_REBUILDUNIT_START 4 /* start rebuild with lowest unit */
#define TWA_OP_REBUILDUNIT_STARTUNIT 5 /* rebuild src_unit (not supported) */
u_int8_t cs:1; /* request state change on src_unit */
u_int8_t logical_subunit; /* for RAID10 rebuild of logical subunit */
} __attribute__ ((packed));
struct twa_command_ata {
u_int8_t opcode:5; /* TWA_OP_ATA_PASSTHROUGH */
u_int8_t sgl_offset:3;
u_int8_t size;
u_int8_t request_id;
u_int8_t unit:4;
u_int8_t host_id:4;
u_int8_t status;
u_int8_t flags;
u_int16_t param;
u_int16_t features;
u_int16_t sector_count;
u_int16_t sector_num;
u_int16_t cylinder_lo;
u_int16_t cylinder_hi;
u_int8_t drive_head;
u_int8_t command;
struct twa_sg sgl[TWA_MAX_ATA_SG_ELEMENTS];
} __attribute__ ((packed));
struct twa_command_generic {
u_int8_t opcode:5;
u_int8_t sgl_offset:3;
u_int8_t size;
u_int8_t request_id;
u_int8_t unit:4;
u_int8_t host_id:4;
u_int8_t status;
u_int8_t flags;
#define TWA_FLAGS_SUCCESS 0x00
#define TWA_FLAGS_INFORMATIONAL 0x01
#define TWA_FLAGS_WARNING 0x02
#define TWA_FLAGS_FATAL 0x03
#define TWA_FLAGS_PERCENTAGE (1<<8) /* bits 0-6 indicate completion percentage */
u_int16_t count; /* block count, parameter count, message credits */
} __attribute__ ((packed));
/* Command packet - must be TWA_ALIGNMENT aligned. */
union twa_command_7k {
struct twa_command_init_connect init_connect;
struct twa_command_download_firmware download_fw;
struct twa_command_reset_firmware reset_fw;
struct twa_command_io io;
struct twa_command_hotswap hotswap;
struct twa_command_param param;
struct twa_command_rebuildunit rebuildunit;
struct twa_command_ata ata;
struct twa_command_generic generic;
} __attribute__ ((packed));
/* 9000 structures. */
/* Command Packet. */
struct twa_command_9k {
struct {
u_int8_t opcode:5;
u_int8_t reserved:3;
} command;
u_int8_t unit;
u_int16_t request_id;
u_int8_t status;
u_int8_t sgl_offset; /* offset (in bytes) to sg_list, from the end of sgl_entries */
u_int16_t sgl_entries;
u_int8_t cdb[16];
struct twa_sg sg_list[TWA_MAX_SG_ELEMENTS];
u_int8_t padding[32];
} __attribute__ ((packed));
/* Command packet header. */
struct twa_command_header {
u_int8_t sense_data[TWA_SENSE_DATA_LENGTH];
struct {
int8_t reserved[4];
u_int16_t error;
u_int8_t padding;
struct {
u_int8_t severity:3;
u_int8_t reserved:5;
} substatus_block;
} status_block;
u_int8_t err_desc[98];
struct {
u_int8_t size_header;
u_int16_t reserved;
u_int8_t size_sense;
} header_desc;
} __attribute__ ((packed));
/* Full command packet. */
struct twa_command_packet {
struct twa_command_header cmd_hdr;
union {
union twa_command_7k cmd_pkt_7k;
struct twa_command_9k cmd_pkt_9k;
} command;
} __attribute__ ((packed));
/* Response queue entry. */
union twa_response_queue {
struct {
u_int32_t undefined_1:4;
u_int32_t response_id:8;
u_int32_t undefined_2:20;
} u;
u_int32_t value;
} __attribute__ ((packed));
#define TWA_AEN_QUEUE_EMPTY 0x00
#define TWA_AEN_SOFT_RESET 0x01
#define TWA_AEN_SYNC_TIME_WITH_HOST 0x31
#define TWA_AEN_SEVERITY_ERROR 0x1
#define TWA_AEN_SEVERITY_WARNING 0x1
#define TWA_AEN_SEVERITY_INFO 0x1
#define TWA_AEN_SEVERITY_DEBUG 0x4
#define TWA_PARAM_VERSION_TABLE 0x0402
#define TWA_PARAM_VERSION_MONITOR 2 /* monitor version [16] */
#define TWA_PARAM_VERSION_FW 3 /* firmware version [16] */
#define TWA_PARAM_VERSION_BIOS 4 /* BIOSs version [16] */
#define TWA_PARAM_VERSION_PCBA 5 /* PCB version [8] */
#define TWA_PARAM_VERSION_ATA 6 /* A-chip version [8] */
#define TWA_PARAM_VERSION_PCI 7 /* P-chip version [8] */
#define TWA_PARAM_CONTROLLER_TABLE 0x0403
#define TWA_PARAM_CONTROLLER_PORT_COUNT 3 /* number of ports [1] */
#define TWA_PARAM_TIME_TABLE 0x40A
#define TWA_PARAM_TIME_SchedulerTime 0x3
#define TWA_9K_PARAM_DESCRIPTOR 0x8000
struct twa_param_9k {
u_int16_t table_id;
u_int8_t parameter_id;
u_int8_t reserved;
u_int16_t parameter_size_bytes;
u_int16_t parameter_actual_size_bytes;
u_int8_t data[1];
} __attribute__ ((packed));
#pragma pack()

View File

@ -386,6 +386,11 @@ static struct witness_order_list_entry order_lists[] = {
{ "pcicfg", &lock_class_mtx_spin },
{ "NDIS thread lock", &lock_class_mtx_spin },
#endif
{ "tw_osl_io_lock", &lock_class_mtx_spin },
{ "tw_osl_q_lock", &lock_class_mtx_spin },
{ "tw_cl_io_lock", &lock_class_mtx_spin },
{ "tw_cl_intr_lock", &lock_class_mtx_spin },
{ "tw_cl_gen_lock", &lock_class_mtx_spin },
{ NULL, NULL },
{ NULL, NULL }
};

View File

@ -1,4 +1,38 @@
# $FreeBSD$
#
# Copyright (c) 2004 Applied Micro Circuits Corporation.
# 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$
#
#
# 3ware driver for 9000 series storage controllers.
#
# Author: Vinod Kashyap
#
#
# In the line following this comment, a value of 0 on the right hand
@ -12,14 +46,18 @@ TWA_FLASH_FIRMWARE?=0
KMOD = twa
.PATH: ${.CURDIR}/../../dev/${KMOD}
SRCS = twa_freebsd.c twa_cam.c twa.c twa_globals.c \
SRCS = tw_osl_freebsd.c tw_osl_cam.c \
tw_cl_init.c tw_cl_io.c tw_cl_intr.c tw_cl_misc.c \
bus_if.h device_if.h pci_if.h opt_scsi.h opt_cam.h opt_twa.h
CFLAGS += -I${.CURDIR}/../../dev/${KMOD}
.if $(TWA_FLASH_FIRMWARE) != 0
CFLAGS+=-DTWA_FLASH_FIRMWARE
SRCS += twa_fwimg.c
CFLAGS += -DTWA_FLASH_FIRMWARE
SRCS += tw_cl_fwimg.c
.endif
#CFLAGS+=-DTWA_DEBUG=0
#CFLAGS += -DTWA_DEBUG=0
.include <bsd.kmod.mk>