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:
parent
59847201f9
commit
050ff127dc
@ -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
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
322
sys/dev/twa/twa.h
Normal 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
703
sys/dev/twa/twa_cam.c
Normal 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
77
sys/dev/twa/twa_externs.h
Normal 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
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
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
247
sys/dev/twa/twa_globals.c
Normal 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 */
|
62
sys/dev/twa/twa_includes.h
Normal file
62
sys/dev/twa/twa_includes.h
Normal 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
125
sys/dev/twa/twa_ioctl.h
Normal 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
463
sys/dev/twa/twa_reg.h
Normal 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()
|
||||
|
@ -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
24
sys/modules/twa/Makefile
Normal 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>
|
Loading…
Reference in New Issue
Block a user