Initial check-in of the device driver for 3ware's 9000 series

PATA/SATA RAID controllers.  This driver is a SIM under CAM, and
so, behaves like a driver for a SCSI controller.
This commit is contained in:
vkashyap 2004-03-30 03:46:00 +00:00
parent 59847201f9
commit 050ff127dc
13 changed files with 29298 additions and 0 deletions

View File

@ -170,6 +170,11 @@ dev/syscons/scvidctl.c optional sc
dev/syscons/scvtb.c optional sc
dev/syscons/syscons.c optional sc
dev/syscons/sysmouse.c optional sc
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/uart/uart_cpu_i386.c optional uart
geom/geom_bsd.c standard
geom/geom_bsd_enc.c standard

2399
sys/dev/twa/twa.c Normal file

File diff suppressed because it is too large Load Diff

322
sys/dev/twa/twa.h Normal file
View File

@ -0,0 +1,322 @@
/*-
* 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
*/
/*
* The scheme for the driver version is:
* <major change>.<external release>.<3ware internal release>.<development release>
*/
#define TWA_DRIVER_VERSION_STRING "2.50.00.000"
#define TWA_CDEV_MAJOR MAJOR_AUTO
#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_IN_PROGRESS (1<<4) /* bus_dmamap_load returned EINPROGRESS */
/* 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 */
size_t tr_length; /* length of buffer being passed to firmware */
void *tr_real_data; /* ptr to, and length of data passed */
size_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_dma_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 */
dev_t 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_dma_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)

703
sys/dev/twa/twa_cam.c Normal file
View File

@ -0,0 +1,703 @@
/*-
* 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_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_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_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;
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]);
cmd_hdr->err_specific_desc[sizeof(cmd_hdr->err_specific_desc) - 1] = '\0';
/*
* 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)))
twa_printf(sc, "SCSI cmd = 0x%x: ERROR: (0x%02X: 0x%04X): %s: %s\n",
cdb[0],
TWA_MESSAGE_SOURCE_CONTROLLER_ERROR,
error,
twa_find_msg_string(twa_error_table, error),
cmd_hdr->err_specific_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. Simply free it. */
if (tr->tr_data)
free(tr->tr_data, M_DEVBUF);
} else {
if ((ccb = tr->tr_private)) {
/* It's a SCSI request. Complete it. */
ccb->ccb_h.status = CAM_SCSI_BUS_RESET |
CAM_RELEASE_SIMQ;
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;
}

77
sys/dev/twa/twa_externs.h Normal file
View File

@ -0,0 +1,77 @@
/*-
* 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 */

1032
sys/dev/twa/twa_freebsd.c Normal file

File diff suppressed because it is too large Load Diff

23838
sys/dev/twa/twa_fwimg.c Normal file

File diff suppressed because it is too large Load Diff

247
sys/dev/twa/twa_globals.c Normal file
View File

@ -0,0 +1,247 @@
/*-
* 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 array"},
{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"},
{0x00FC, "Recovered/finished array membership update"},
{0x00FD, "Handler lockup"},
{0x00FE, "Retrying PCI transfer"},
{0x00FF, "AEN queue is full"},
{0xFFFFFFFF, (char *)NULL}
};
/* AEN severity table. */
char *twa_aen_severity_table[] = {
"None",
"ERROR",
"WARNING",
"INFO",
"DEBUG",
(char *)NULL
};
/* 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, "Replace 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"},
{0x0130, "Invalid stripe handle"},
{0x0131, "Handle that was not locked"},
{0x0132, "Handle that was not empy"},
{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"},
{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, "Host PCI bus abort"},
{0x0212, "Host 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, "Image downloaded overflowed buffer"},
{0x0240, "I2C device not found"},
{0x0241, "I2C transaction aborted"},
{0x0242, "SO-DIMM parameter(s) incompatible using defaults"},
{0x0243, "SO-DIMM unsupported"},
{0x0248, "SPI transfer status error"},
{0x0249, "SPI transfer timeout error"},
{0x0250, "Invalid unit descriptor size in CreateUnit"},
{0x0251, "Unit descriptor size exceeds data buffer in CreateUnit"},
{0x0252, "Invalid value in CreateUnit descriptor"},
{0x0253, "Inadequate disk space to support descriptor in CreateUnit"},
{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 does not support this descriptor version"},
{0x0258, "Invalid subunit for RAID 0 or 5 in CreateUnit"},
{0x0259, "Too many descriptors in CreateUnit"},
{0x025A, "Invalid configuration specified in CreateUnit descriptor"},
{0x025B, "Invalid LBA offset specified in CreateUnit descriptor"},
{0x025C, "Invalid stripelet size specified in CreateUnit descriptor"},
{0x0260, "SMART attribute exceeded threshold"},
{0xFFFFFFFF, (char *)NULL}
};
#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

@ -0,0 +1,62 @@
/*-
* 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 <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/kernel.h>
#include <sys/sysctl.h>
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/disk.h>
#include <sys/stat.h>
#include <sys/devicestat.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <machine/clock.h>
#include <vm/vm.h>
#include <sys/rman.h>
#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>

125
sys/dev/twa/twa_ioctl.h Normal file
View File

@ -0,0 +1,125 @@
/*-
* 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[484];
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[484];
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)

463
sys/dev/twa/twa_reg.h Normal file
View File

@ -0,0 +1,463 @@
/*-
* 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_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 0x17
#define TWA_BASE_FW_BRANCH 0
#define TWA_BASE_FW_BUILD 1
#define TWA_CURRENT_FW_SRL 0x18
#define TWA_CURRENT_FW_BRANCH 1
#define TWA_CURRENT_FW_BUILD 9
#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;
bus_size_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_specific_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

@ -124,6 +124,7 @@ device dpt # DPT Smartcache III, IV - See NOTES for options
device iir # Intel Integrated RAID
device ips # IBM (Adaptec) ServeRAID
device mly # Mylex AcceleRAID/eXtremeRAID
device twa # 3ware 9000 series PATA/SATA RAID
# RAID controllers
device aac # Adaptec FSA RAID

24
sys/modules/twa/Makefile Normal file
View File

@ -0,0 +1,24 @@
# $FreeBSD$
#
# Uncomment the following line to bundle firmware with the driver,
# which may be flashed onto the controller, if the firmware on the
# controller is older than the one bundled, and needs to be upgraded.
# The size of the driver will increase significantly (to over 500KB)
# if this option is selected.
#
FLASH_FIRMWARE=1
KMOD = twa
.PATH: ${.CURDIR}/../../dev/${KMOD}
SRCS = twa_freebsd.c twa_cam.c twa.c twa_globals.c \
bus_if.h device_if.h pci_if.h opt_scsi.h opt_cam.h opt_twa.h
.if defined(FLASH_FIRMWARE)
CFLAGS+=-DTWA_FLASH_FIRMWARE
SRCS += twa_fwimg.c
.endif
#CFLAGS+=-DTWA_DEBUG=0
.include <bsd.kmod.mk>