A large set of changes:

+ Add boatloads of KASSERTs and *really* check out more locking
issues (to catch recursions when we actually go to real locking
in CAM soon). The KASSERTs also caught lots of other issues like
using commands that were put back on free lists, etc.

+ Target mode: role setting is derived directly from port capabilities.
There is no need to set a role any more. Some target mode resources
are allocated early on (ELS), but target command buffer allocation
is deferred until the first lun enable.

+ Fix some breakages I introduced with target mode in that some commands
are *repeating* commands. That is, the reply shows up but the command
isn't really done (we don't free it). We still need to take it off the
pending list because when we resubmit it, bad things then  happen.

+ Fix more of the way that timed out commands and bus reset is done. The
actual TMF response code was being ignored.

+ For SPI, honor BIOS settings. This doesn't quite fix the problems we've
seen where we can't seem to (re)negotiate U320 on all drives but avoids
it instead by letting us honor the BIOS settings. I'm sure this is not
quite right and will have to change again soon.
This commit is contained in:
Matt Jacob 2006-04-11 16:47:30 +00:00
parent 4548510be1
commit 5089bd63bd
5 changed files with 969 additions and 626 deletions

View file

@ -665,6 +665,7 @@ mpt_intr(void *arg)
int ntrips = 0;
mpt = (struct mpt_softc *)arg;
mpt_lprt(mpt, MPT_PRT_DEBUG2, "enter mpt_intr\n");
while ((reply_desc = mpt_pop_reply_queue(mpt)) != MPT_REPLY_EMPTY) {
request_t *req;
MSG_DEFAULT_REPLY *reply_frame;
@ -789,6 +790,7 @@ mpt_intr(void *arg)
break;
}
}
mpt_lprt(mpt, MPT_PRT_DEBUG2, "exit mpt_intr\n");
}
/******************************* Error Recovery *******************************/
@ -1138,18 +1140,29 @@ mpt_free_request(struct mpt_softc *mpt, request_t *req)
req->chain = NULL;
mpt_free_request(mpt, nxt); /* NB: recursion */
}
KASSERT(req->state != REQ_STATE_FREE, ("freeing free request"));
KASSERT(!(req->state & REQ_STATE_LOCKED), ("freeing locked request"));
KASSERT(MPT_OWNED(mpt), ("mpt_free_request: mpt not locked\n"));
KASSERT(mpt_req_on_free_list(mpt, req) == 0,
("mpt_free_request: req %p:%u func %x already on freelist",
req, req->serno, ((MSG_REQUEST_HEADER *)req->req_vbuf)->Function));
KASSERT(mpt_req_on_pending_list(mpt, req) == 0,
("mpt_free_request: req %p:%u func %x on pending list",
req, req->serno, ((MSG_REQUEST_HEADER *)req->req_vbuf)->Function));
#ifdef INVARIANTS
mpt_req_not_spcl(mpt, req, "mpt_free_request", __LINE__);
#endif
req->ccb = NULL;
if (LIST_EMPTY(&mpt->ack_frames)) {
/*
* Insert free ones at the tail
*/
req->serno = 0;
req->state = REQ_STATE_FREE;
#ifdef INVARIANTS
memset(req->req_vbuf, 0xff, sizeof (MSG_REQUEST_HEADER));
#endif
TAILQ_INSERT_TAIL(&mpt->request_free_list, req, links);
if (mpt->getreqwaiter != 0) {
mpt->getreqwaiter = 0;
@ -1164,9 +1177,7 @@ mpt_free_request(struct mpt_softc *mpt, request_t *req)
record = LIST_FIRST(&mpt->ack_frames);
LIST_REMOVE(record, links);
req->state = REQ_STATE_ALLOCATED;
if ((req->serno = mpt->sequence++) == 0) {
req->serno = mpt->sequence++;
}
mpt_assign_serno(mpt, req);
mpt_send_event_ack(mpt, req, &record->reply, record->context);
reply_baddr = (uint32_t)((uint8_t *)record - mpt->reply)
+ (mpt->reply_phys & 0xFFFFFFFF);
@ -1180,18 +1191,19 @@ mpt_get_request(struct mpt_softc *mpt, int sleep_ok)
request_t *req;
retry:
KASSERT(MPT_OWNED(mpt), ("mpt_get_request: mpt not locked\n"));
req = TAILQ_FIRST(&mpt->request_free_list);
if (req != NULL) {
KASSERT(req == &mpt->request_pool[req->index],
("mpt_get_request: corrupted request free list\n"));
KASSERT(req->state == REQ_STATE_FREE,
("req not free on free list %x", req->state));
("req %p:%u not free on free list %x index %d function %x",
req, req->serno, req->state, req->index,
((MSG_REQUEST_HEADER *)req->req_vbuf)->Function));
TAILQ_REMOVE(&mpt->request_free_list, req, links);
req->state = REQ_STATE_ALLOCATED;
req->chain = NULL;
if ((req->serno = mpt->sequence++) == 0) {
req->serno = mpt->sequence++;
}
mpt_assign_serno(mpt, req);
} else if (sleep_ok != 0) {
mpt->getreqwaiter = 1;
mpt_sleep(mpt, &mpt->request_free_list, PUSER, "mptgreq", 0);
@ -1228,6 +1240,12 @@ mpt_send_cmd(struct mpt_softc *mpt, request_t *req)
bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap,
BUS_DMASYNC_PREWRITE);
req->state |= REQ_STATE_QUEUED;
KASSERT(mpt_req_on_free_list(mpt, req) == 0,
("req %p:%u func %x on freelist list in mpt_send_cmd",
req, req->serno, ((MSG_REQUEST_HEADER *)req->req_vbuf)->Function));
KASSERT(mpt_req_on_pending_list(mpt, req) == 0,
("req %p:%u func %x already on pending list in mpt_send_cmd",
req, req->serno, ((MSG_REQUEST_HEADER *)req->req_vbuf)->Function));
TAILQ_INSERT_HEAD(&mpt->request_pending_list, req, links);
mpt_write(mpt, MPT_OFFSET_REQUEST_Q, (uint32_t) req->req_pbuf);
}
@ -1867,8 +1885,7 @@ mpt_send_port_enable(struct mpt_softc *mpt, int port)
mpt_send_cmd(mpt, req);
error = mpt_wait_req(mpt, req, REQ_STATE_DONE, REQ_STATE_DONE,
/*sleep_ok*/FALSE,
/*time_ms*/(mpt->is_sas || mpt->is_fc)? 30000 : 3000);
FALSE, (mpt->is_sas || mpt->is_fc)? 30000 : 3000);
if (error != 0) {
mpt_prt(mpt, "port %d enable timed out\n", port);
return (-1);
@ -2113,7 +2130,7 @@ mpt_core_enable(struct mpt_softc *mpt)
mpt_intr(mpt);
/*
* Enable the port- but only if we are not MPT_ROLE_NONE.
* Enable the port.
*/
if (mpt_send_port_enable(mpt, 0) != MPT_OK) {
mpt_prt(mpt, "failed to enable port 0\n");
@ -2446,38 +2463,22 @@ mpt_configure_ioc(struct mpt_softc *mpt)
mpt->mpt_max_devices = pfp.MaxDevices;
/*
* Match our expected role with what this port supports.
*
* We only do this to meet expectations. That is, if the
* user has specified they want initiator role, and we
* don't support it, that's an error we return back upstream.
* Set our expected role with what this port supports.
*/
mpt->cap = MPT_ROLE_NONE;
mpt->role = MPT_ROLE_NONE;
if (pfp.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_INITIATOR) {
mpt->cap |= MPT_ROLE_INITIATOR;
mpt->role |= MPT_ROLE_INITIATOR;
}
if (pfp.ProtocolFlags & MPI_PORTFACTS_PROTOCOL_TARGET) {
mpt->cap |= MPT_ROLE_TARGET;
mpt->role |= MPT_ROLE_TARGET;
}
if (mpt->cap == MPT_ROLE_NONE) {
if (mpt->role == MPT_ROLE_NONE) {
mpt_prt(mpt, "port does not support either target or "
"initiator role\n");
return (ENXIO);
}
if ((mpt->role & MPT_ROLE_INITIATOR) &&
(mpt->cap & MPT_ROLE_INITIATOR) == 0) {
mpt_prt(mpt, "port does not support initiator role\n");
return (ENXIO);
}
if ((mpt->role & MPT_ROLE_TARGET) &&
(mpt->cap & MPT_ROLE_TARGET) == 0) {
mpt_prt(mpt, "port does not support target role\n");
return (ENXIO);
}
if (mpt_enable_ioc(mpt, 0) != MPT_OK) {
mpt_prt(mpt, "unable to initialize IOC\n");
return (ENXIO);

View file

@ -294,7 +294,8 @@ struct req_entry {
mpt_req_state_t state; /* Request State Information */
uint16_t index; /* Index of this entry */
uint16_t IOCStatus; /* Completion status */
uint32_t serno; /* serial number */
uint16_t ResponseCode; /* TMF Reponse Code */
uint16_t serno; /* serial number */
union ccb *ccb; /* CAM request */
void *req_vbuf; /* Virtual Address of Entry */
void *sense_vbuf; /* Virtual Address of sense data */
@ -355,7 +356,7 @@ typedef struct {
struct mpt_hdr_stailq inots;
int enabled;
} tgt_resource_t;
#define MPT_MAX_ELS 8
#define MPT_MAX_ELS 64
/**************************** Handler Registration ****************************/
/*
@ -478,10 +479,11 @@ LIST_HEAD(mpt_evtf_list, mpt_evtf_record);
struct mpt_softc {
device_t dev;
#if __FreeBSD_version < 500000
int mpt_splsaved;
uint32_t mpt_islocked;
int mpt_splsaved;
#else
struct mtx mpt_lock;
int mpt_locksetup;
#endif
uint32_t mpt_pers_mask;
uint32_t : 8,
@ -489,14 +491,14 @@ struct mpt_softc {
: 1,
twildcard : 1,
tenabled : 1,
cap : 2, /* none, ini, target, both */
: 2,
role : 2, /* none, ini, target, both */
raid_mwce_set : 1,
getreqwaiter : 1,
shutdwn_raid : 1,
shutdwn_recovery: 1,
outofbeer : 1,
mpt_locksetup : 1,
: 1,
disabled : 1,
is_sas : 1,
is_fc : 1;
@ -534,8 +536,6 @@ struct mpt_softc {
CONFIG_PAGE_SCSI_DEVICE_1 _dev_page1[16];
uint16_t _tag_enable;
uint16_t _disc_enable;
uint16_t _update_params0;
uint16_t _update_params1;
} spi;
#define mpt_port_page0 cfg.spi._port_page0
#define mpt_port_page1 cfg.spi._port_page1
@ -544,8 +544,6 @@ struct mpt_softc {
#define mpt_dev_page1 cfg.spi._dev_page1
#define mpt_tag_enable cfg.spi._tag_enable
#define mpt_disc_enable cfg.spi._disc_enable
#define mpt_update_params0 cfg.spi._update_params0
#define mpt_update_params1 cfg.spi._update_params1
struct mpi_fc_cfg {
CONFIG_PAGE_FC_PORT_0 _port_page0;
#define mpt_fcport_page0 cfg.fc._port_page0
@ -637,6 +635,7 @@ struct mpt_softc {
*/
uint32_t scsi_tgt_handler_id;
request_t ** tgt_cmd_ptrs;
request_t ** els_cmd_ptrs; /* FC only */
/*
* *snork*- this is chosen to be here *just in case* somebody
@ -646,11 +645,12 @@ struct mpt_softc {
tgt_resource_t trt_wildcard; /* wildcard luns */
tgt_resource_t trt[MPT_MAX_LUNS];
uint16_t tgt_cmds_allocated;
uint16_t padding1;
uint16_t els_cmds_allocated; /* FC only */
uint16_t timeouts; /* timeout count */
uint16_t success; /* successes afer timeout */
uint32_t sequence; /* Sequence Number */
uint16_t sequence; /* Sequence Number */
uint16_t pad3;
/* Opposing port in a 929 or 1030, or NULL */
@ -669,11 +669,22 @@ struct mpt_softc {
TAILQ_ENTRY(mpt_softc) links;
};
static __inline void mpt_assign_serno(struct mpt_softc *, request_t *);
static __inline void
mpt_assign_serno(struct mpt_softc *mpt, request_t *req)
{
if ((req->serno = mpt->sequence++) == 0) {
req->serno = mpt->sequence++;
}
}
/***************************** Locking Primitives *****************************/
#if __FreeBSD_version < 500000
#define MPT_IFLAGS INTR_TYPE_CAM
#define MPT_LOCK(mpt) mpt_lockspl(mpt)
#define MPT_UNLOCK(mpt) mpt_unlockspl(mpt)
#define MPT_OWNED(mpt) mpt->mpt_islocked
#define MPTLOCK_2_CAMLOCK MPT_UNLOCK
#define CAMLOCK_2_MPTLOCK MPT_LOCK
#define MPT_LOCK_SETUP(mpt)
@ -741,22 +752,56 @@ mpt_sleep(struct mpt_softc *mpt, void *ident, int priority,
#define MPT_LOCK(mpt) mtx_lock(&(mpt)->mpt_lock)
#define MPT_UNLOCK(mpt) mtx_unlock(&(mpt)->mpt_lock)
#define MPT_OWNED(mpt) mtx_owned(&(mpt)->mpt_lock)
#define MPTLOCK_2_CAMLOCK(mpt) \
mtx_unlock(&(mpt)->mpt_lock); mtx_lock(&Giant)
#define CAMLOCK_2_MPTLOCK(mpt) \
mtx_unlock(&Giant); mtx_lock(&(mpt)->mpt_lock)
#define mpt_sleep(mpt, ident, priority, wmesg, timo) \
msleep(ident, &(mpt)->mpt_lock, priority, wmesg, timo)
#else
#define MPT_IFLAGS INTR_TYPE_CAM | INTR_ENTROPY
#define MPT_LOCK_SETUP(mpt) do { } while (0)
#define MPT_LOCK_DESTROY(mpt) do { } while (0)
#define MPT_LOCK(mpt) do { } while (0)
#define MPT_UNLOCK(mpt) do { } while (0)
#define MPTLOCK_2_CAMLOCK(mpt) do { } while (0)
#define CAMLOCK_2_MPTLOCK(mpt) do { } while (0)
#define mpt_sleep(mpt, ident, priority, wmesg, timo) \
tsleep(ident, priority, wmesg, timo)
#if 0
#define MPT_LOCK(mpt) \
device_printf(mpt->dev, "LOCK %s:%d\n", __FILE__, __LINE__); \
KASSERT(mpt->mpt_locksetup == 0, \
("recursive lock acquire at %s:%d", __FILE__, __LINE__)); \
mpt->mpt_locksetup = 1
#define MPT_UNLOCK(mpt) \
device_printf(mpt->dev, "UNLK %s:%d\n", __FILE__, __LINE__); \
KASSERT(mpt->mpt_locksetup == 1, \
("release unowned lock at %s:%d", __FILE__, __LINE__)); \
mpt->mpt_locksetup = 0
#else
#define MPT_LOCK(mpt) \
KASSERT(mpt->mpt_locksetup == 0, \
("recursive lock acquire at %s:%d", __FILE__, __LINE__)); \
mpt->mpt_locksetup = 1
#define MPT_UNLOCK(mpt) \
KASSERT(mpt->mpt_locksetup == 1, \
("release unowned lock at %s:%d", __FILE__, __LINE__)); \
mpt->mpt_locksetup = 0
#endif
#define MPT_OWNED(mpt) mpt->mpt_locksetup
#define MPTLOCK_2_CAMLOCK(mpt) MPT_UNLOCK(mpt)
#define CAMLOCK_2_MPTLOCK(mpt) MPT_LOCK(mpt)
static __inline int
mpt_sleep(struct mpt_softc *, void *, int, const char *, int);
static __inline int
mpt_sleep(struct mpt_softc *mpt, void *i, int p, const char *w, int t)
{
int r;
MPT_UNLOCK(mpt);
r = tsleep(i, p, w, t);
MPT_LOCK(mpt);
return (r);
}
#endif
#endif
@ -902,6 +947,11 @@ enum {
MPT_PRT_TRACE,
MPT_PRT_NONE=100
};
#ifdef INVARIANTS
#define MPT_PRT_INVARIANT MPT_PRT_ALWAYS
#else
#define MPT_PRT_INVARIANT MPT_PRT_DEBUG
#endif
#if __FreeBSD_version > 500000
#define mpt_lprt(mpt, level, ...) \
@ -955,6 +1005,93 @@ mpt_tag_2_req(struct mpt_softc *mpt, uint32_t tag)
KASSERT(mpt->tgt_cmd_ptrs[rtg], ("no cmd backpointer"));
return (mpt->tgt_cmd_ptrs[rtg]);
}
static __inline int
mpt_req_on_free_list(struct mpt_softc *, request_t *);
static __inline int
mpt_req_on_pending_list(struct mpt_softc *, request_t *);
static __inline void
mpt_req_spcl(struct mpt_softc *, request_t *, const char *, int);
static __inline void
mpt_req_not_spcl(struct mpt_softc *, request_t *, const char *, int);
/*
* Is request on freelist?
*/
static __inline int
mpt_req_on_free_list(struct mpt_softc *mpt, request_t *req)
{
request_t *lrq;
TAILQ_FOREACH(lrq, &mpt->request_free_list, links) {
if (lrq == req) {
return (1);
}
}
return (0);
}
/*
* Is request on pending list?
*/
static __inline int
mpt_req_on_pending_list(struct mpt_softc *mpt, request_t *req)
{
request_t *lrq;
TAILQ_FOREACH(lrq, &mpt->request_pending_list, links) {
if (lrq == req) {
return (1);
}
}
return (0);
}
/*
* Make sure that req *is* part of one of the special lists
*/
static __inline void
mpt_req_spcl(struct mpt_softc *mpt, request_t *req, const char *s, int line)
{
int i;
for (i = 0; i < mpt->els_cmds_allocated; i++) {
if (req == mpt->els_cmd_ptrs[i]) {
return;
}
}
for (i = 0; i < mpt->tgt_cmds_allocated; i++) {
if (req == mpt->tgt_cmd_ptrs[i]) {
return;
}
}
panic("%s(%d): req %p:%u function %x not in els or tgt ptrs\n",
s, line, req, req->serno,
((PTR_MSG_REQUEST_HEADER)req->req_vbuf)->Function);
}
/*
* Make sure that req is *not* part of one of the special lists.
*/
static __inline void
mpt_req_not_spcl(struct mpt_softc *mpt, request_t *req, const char *s, int line)
{
int i;
for (i = 0; i < mpt->els_cmds_allocated; i++) {
KASSERT(req != mpt->els_cmd_ptrs[i],
("%s(%d): req %p:%u func %x in els ptrs at ioindex %d\n",
s, line, req, req->serno,
((PTR_MSG_REQUEST_HEADER)req->req_vbuf)->Function, i));
}
for (i = 0; i < mpt->tgt_cmds_allocated; i++) {
KASSERT(req != mpt->tgt_cmd_ptrs[i],
("%s(%d): req %p:%u func %x in tgt ptrs at ioindex %d\n",
s, line, req, req->serno,
((PTR_MSG_REQUEST_HEADER)req->req_vbuf)->Function, i));
}
}
#endif
typedef enum {

File diff suppressed because it is too large Load diff

View file

@ -254,7 +254,6 @@ mpt_set_options(struct mpt_softc *mpt)
mpt->disabled = 1;
}
}
bitmap = 0;
if (getenv_int("mpt_debug", &bitmap)) {
if (bitmap & (1 << mpt->unit)) {
@ -262,21 +261,21 @@ mpt_set_options(struct mpt_softc *mpt)
}
}
bitmap = 0;
if (getenv_int("mpt_target", &bitmap)) {
if (getenv_int("mpt_debug1", &bitmap)) {
if (bitmap & (1 << mpt->unit)) {
mpt->role = MPT_ROLE_TARGET;
mpt->verbose = MPT_PRT_DEBUG1;
}
}
bitmap = 0;
if (getenv_int("mpt_none", &bitmap)) {
if (getenv_int("mpt_debug2", &bitmap)) {
if (bitmap & (1 << mpt->unit)) {
mpt->role = MPT_ROLE_NONE;
mpt->verbose = MPT_PRT_DEBUG2;
}
}
bitmap = 0;
if (getenv_int("mpt_initiator", &bitmap)) {
if (getenv_int("mpt_debug3", &bitmap)) {
if (bitmap & (1 << mpt->unit)) {
mpt->role = MPT_ROLE_INITIATOR;
mpt->verbose = MPT_PRT_DEBUG3;
}
}
}
@ -311,9 +310,9 @@ mpt_link_peer(struct mpt_softc *mpt)
{
struct mpt_softc *mpt2;
if (mpt->unit == 0)
if (mpt->unit == 0) {
return;
}
/*
* XXX: depends on probe order
*/
@ -336,6 +335,14 @@ mpt_link_peer(struct mpt_softc *mpt)
}
}
static void
mpt_unlink_peer(struct mpt_softc *mpt)
{
if (mpt->mpt2) {
mpt->mpt2->mpt2 = NULL;
}
}
static int
mpt_pci_attach(device_t dev)
@ -377,7 +384,7 @@ mpt_pci_attach(device_t dev)
mpt->raid_mwce_setting = MPT_RAID_MWCE_DEFAULT;
mpt->raid_queue_depth = MPT_RAID_QUEUE_DEPTH_DEFAULT;
mpt->verbose = MPT_PRT_NONE;
mpt->role = MPT_ROLE_DEFAULT;
mpt->role = MPT_ROLE_NONE;
mpt_set_options(mpt);
if (mpt->verbose == MPT_PRT_NONE) {
mpt->verbose = MPT_PRT_WARN;
@ -388,7 +395,7 @@ mpt_pci_attach(device_t dev)
cmd = pci_read_config(dev, PCIR_COMMAND, 2);
if ((cmd & PCIM_CMD_MEMEN) == 0) {
device_printf(dev, "Memory accesses disabled");
goto bad;
return (ENXIO);
}
/*
@ -498,21 +505,6 @@ mpt_pci_attach(device_t dev)
*/
pci_disable_io(dev, SYS_RES_IOPORT);
switch (mpt->role) {
case MPT_ROLE_TARGET:
break;
case MPT_ROLE_INITIATOR:
break;
case MPT_ROLE_TARGET|MPT_ROLE_INITIATOR:
mpt->disabled = 1;
mpt_prt(mpt, "dual roles unsupported\n");
goto bad;
case MPT_ROLE_NONE:
device_printf(dev, "role of NONE same as disable\n");
mpt->disabled = 1;
goto bad;
}
/* Initialize the hardware */
if (mpt->disabled == 0) {
MPT_LOCK(mpt);
@ -536,11 +528,15 @@ mpt_pci_attach(device_t dev)
MPT_UNLOCK(mpt);
goto bad;
}
KASSERT(MPT_OWNED(mpt) == 0, ("leaving attach with device locked"));
return (0);
bad:
mpt_dma_mem_free(mpt);
mpt_free_bus_resources(mpt);
mpt_unlink_peer(mpt);
MPT_LOCK_DESTROY(mpt);
/*
* but return zero to preserve unit numbering

View file

@ -277,7 +277,9 @@ mpt_raid_attach(struct mpt_softc *mpt)
csa.event_enable = AC_FOUND_DEVICE;
csa.callback = mpt_raid_async;
csa.callback_arg = mpt;
MPTLOCK_2_CAMLOCK(mpt);
xpt_action((union ccb *)&csa);
CAMLOCK_2_MPTLOCK(mpt);
if (csa.ccb_h.status != CAM_REQ_CMP) {
mpt_prt(mpt, "mpt_raid_attach: Unable to register "
"CAM async handler.\n");
@ -307,7 +309,9 @@ mpt_raid_detach(struct mpt_softc *mpt)
csa.event_enable = 0;
csa.callback = mpt_raid_async;
csa.callback_arg = mpt;
MPTLOCK_2_CAMLOCK(mpt);
xpt_action((union ccb *)&csa);
CAMLOCK_2_MPTLOCK(mpt);
}
static void