Do initial cut of SAS HBA support. These controllers (106X) seem to support

automatically both SATA and SAS drives.  The async SAS event handling we catch
but ignore at present (so automagic attach/detach isn't hooked up yet).

Do 64 bit PCI support- we can now work on systems with > 4GB of memory.

Do large transfer support- we now can support up to reported chain depth, or
the length of our request area. We simply allocate additional request elements
when we would run out of room for chain lists.

Tested on Ultra320, FC and SAS controllers on AMD64 and i386 platforms.
There were no RAID cards available for me to regression test.

The error recovery for this driver still is pretty bad.
This commit is contained in:
mjacob 2006-02-11 01:35:29 +00:00
parent c1c4403ced
commit 78626b5d46
5 changed files with 606 additions and 242 deletions

View File

@ -88,6 +88,7 @@ static mpt_reply_handler_t mpt_handshake_reply_handler;
static mpt_reply_handler_t mpt_event_reply_handler;
static void mpt_send_event_ack(struct mpt_softc *mpt, request_t *ack_req,
MSG_EVENT_NOTIFY_REPLY *msg, uint32_t context);
static int mpt_send_event_request(struct mpt_softc *mpt, int onoff);
static int mpt_soft_reset(struct mpt_softc *mpt);
static void mpt_hard_reset(struct mpt_softc *mpt);
static int mpt_configure_ioc(struct mpt_softc *mpt);
@ -277,8 +278,9 @@ mpt_stdattach(struct mpt_softc *mpt)
}
int
mpt_stdevent(struct mpt_softc *mpt, request_t *req, MSG_EVENT_NOTIFY_REPLY *rep)
mpt_stdevent(struct mpt_softc *mpt, request_t *req, MSG_EVENT_NOTIFY_REPLY *msg)
{
mpt_lprt(mpt, MPT_PRT_DEBUG, "mpt_stdevent: 0x%x\n", msg->Event & 0xFF);
/* Event was not for us. */
return (0);
}
@ -468,10 +470,17 @@ mpt_event_reply_handler(struct mpt_softc *mpt, request_t *req,
MPT_PERS_FOREACH(mpt, pers)
handled += pers->event(mpt, req, msg);
if (handled == 0)
if (handled == 0 && mpt->mpt_pers_mask == 0) {
mpt_lprt(mpt, MPT_PRT_WARN,
"No Handlers For Any Event Notify Frames. "
"Event %#x (ACK %sequired).\n",
msg->Event, msg->AckRequired? "r" : "not r");
} else if (handled == 0) {
mpt_prt(mpt,
"Unhandled Event Notify Frame. Event %#x.\n",
msg->Event);
"Unhandled Event Notify Frame. Event %#x "
"(ACK %sequired).\n",
msg->Event, msg->AckRequired? "r" : "not r");
}
if (msg->AckRequired) {
request_t *ack_req;
@ -525,6 +534,8 @@ static int
mpt_core_event(struct mpt_softc *mpt, request_t *req,
MSG_EVENT_NOTIFY_REPLY *msg)
{
mpt_lprt(mpt, MPT_PRT_DEBUG, "mpt_core_event: 0x%x\n",
msg->Event & 0xFF);
switch(msg->Event & 0xFF) {
case MPI_EVENT_NONE:
break;
@ -547,6 +558,8 @@ mpt_core_event(struct mpt_softc *mpt, request_t *req,
* of our mpt_send_event_request.
*/
break;
case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
break;
default:
return (/*handled*/0);
break;
@ -922,6 +935,7 @@ mpt_reset(struct mpt_softc *mpt, int reinit)
void
mpt_free_request(struct mpt_softc *mpt, request_t *req)
{
request_t *nxt;
struct mpt_evtf_record *record;
uint32_t reply_baddr;
@ -929,6 +943,10 @@ mpt_free_request(struct mpt_softc *mpt, request_t *req)
panic("mpt_free_request bad req ptr\n");
return;
}
if ((nxt = req->chain) != NULL) {
req->chain = NULL;
mpt_free_request(mpt, nxt); /* NB: recursion */
}
req->ccb = NULL;
req->state = REQ_STATE_FREE;
if (LIST_EMPTY(&mpt->ack_frames)) {
@ -964,6 +982,7 @@ retry:
("mpt_get_request: corrupted request free list\n"));
TAILQ_REMOVE(&mpt->request_free_list, req, links);
req->state = REQ_STATE_ALLOCATED;
req->chain = NULL;
} else if (sleep_ok != 0) {
mpt->getreqwaiter = 1;
mpt_sleep(mpt, &mpt->request_free_list, PUSER, "mptgreq", 0);
@ -979,17 +998,19 @@ mpt_send_cmd(struct mpt_softc *mpt, request_t *req)
uint32_t *pReq;
pReq = req->req_vbuf;
mpt_lprt(mpt, MPT_PRT_TRACE, "Send Request %d (0x%x):\n",
req->index, req->req_pbuf);
mpt_lprt(mpt, MPT_PRT_TRACE, "%08x %08x %08x %08x\n",
pReq[0], pReq[1], pReq[2], pReq[3]);
mpt_lprt(mpt, MPT_PRT_TRACE, "%08x %08x %08x %08x\n",
pReq[4], pReq[5], pReq[6], pReq[7]);
mpt_lprt(mpt, MPT_PRT_TRACE, "%08x %08x %08x %08x\n",
pReq[8], pReq[9], pReq[10], pReq[11]);
mpt_lprt(mpt, MPT_PRT_TRACE, "%08x %08x %08x %08x\n",
pReq[12], pReq[13], pReq[14], pReq[15]);
if (mpt->verbose > MPT_PRT_TRACE) {
int offset;
mpt_prt(mpt, "Send Request %d (0x%x):",
req->index, req->req_pbuf);
for (offset = 0; offset < mpt->request_frame_size; offset++) {
if ((offset & 0x7) == 0) {
mpt_prtc(mpt, "\n");
mpt_prt(mpt, " ");
}
mpt_prtc(mpt, " %08x", pReq[offset]);
}
mpt_prtc(mpt, "\n");
}
bus_dmamap_sync(mpt->request_dmat, mpt->request_dmap,
BUS_DMASYNC_PREWRITE);
req->state |= REQ_STATE_QUEUED;
@ -1028,11 +1049,11 @@ mpt_wait_req(struct mpt_softc *mpt, request_t *req,
timeout = (time_ms * hz) / 1000;
else
timeout = time_ms * 2;
saved_cnt = mpt->reset_cnt;
req->state |= REQ_STATE_NEED_WAKEUP;
mask &= ~REQ_STATE_NEED_WAKEUP;
saved_cnt = mpt->reset_cnt;
while ((req->state & mask) != state
&& mpt->reset_cnt == saved_cnt) {
&& mpt->reset_cnt == saved_cnt) {
if (sleep_ok != 0) {
error = mpt_sleep(mpt, req, PUSER, "mptreq", timeout);
@ -1052,7 +1073,7 @@ mpt_wait_req(struct mpt_softc *mpt, request_t *req,
req->state &= ~REQ_STATE_NEED_WAKEUP;
if (mpt->reset_cnt != saved_cnt)
return (EIO);
if (time_ms && timeout == 0)
if (time_ms && timeout <= 0)
return (ETIMEDOUT);
return (0);
}
@ -1245,12 +1266,20 @@ mpt_send_ioc_init(struct mpt_softc *mpt, uint32_t who)
init.Function = MPI_FUNCTION_IOC_INIT;
if (mpt->is_fc) {
init.MaxDevices = 255;
} else if (mpt->is_sas) {
init.MaxDevices = mpt->mpt_max_devices;
} else {
init.MaxDevices = 16;
}
init.MaxBuses = 1;
init.ReplyFrameSize = MPT_REPLY_SIZE;
init.MsgVersion = htole16(MPI_VERSION);
init.HeaderVersion = htole16(MPI_HEADER_VERSION);
init.ReplyFrameSize = htole16(MPT_REPLY_SIZE);
init.MsgContext = htole32(MPT_REPLY_HANDLER_HANDSHAKE);
if (mpt->ioc_facts_flags & MPI_IOCFACTS_FLAGS_REPLY_FIFO_HOST_SIGNAL) {
init.Flags |= MPI_IOCINIT_FLAGS_REPLY_FIFO_HOST_SIGNAL;
}
if ((error = mpt_send_handshake_cmd(mpt, sizeof init, &init)) != 0) {
return(error);
@ -1826,9 +1855,9 @@ 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*/500);
/*sleep_ok*/FALSE, /*time_ms*/mpt->is_sas? 30000 : 3000);
if (error != 0) {
mpt_prt(mpt, "port enable timed out");
mpt_prt(mpt, "port enable timed out\n");
return (-1);
}
mpt_free_request(mpt, req);
@ -1919,6 +1948,7 @@ mpt_attach(struct mpt_softc *mpt)
pers->use_count++;
}
}
return (0);
}
@ -2060,11 +2090,13 @@ mpt_diag_outsl(struct mpt_softc *mpt, uint32_t addr,
uint32_t *data_end;
data_end = data + (roundup2(len, sizeof(uint32_t)) / 4);
pci_enable_io(mpt->dev, SYS_RES_IOPORT);
mpt_pio_write(mpt, MPT_OFFSET_DIAG_ADDR, addr);
while (data != data_end) {
mpt_pio_write(mpt, MPT_OFFSET_DIAG_DATA, *data);
data++;
}
pci_disable_io(mpt->dev, SYS_RES_IOPORT);
}
static int
@ -2102,6 +2134,7 @@ mpt_download_fw(struct mpt_softc *mpt)
ext->ImageSize);
}
pci_enable_io(mpt->dev, SYS_RES_IOPORT);
/* Setup the address to jump to on reset. */
mpt_pio_write(mpt, MPT_OFFSET_DIAG_ADDR, fw_hdr->IopResetRegAddr);
mpt_pio_write(mpt, MPT_OFFSET_DIAG_DATA, fw_hdr->IopResetVectorValue);
@ -2116,6 +2149,8 @@ mpt_download_fw(struct mpt_softc *mpt)
mpt_pio_write(mpt, MPT_OFFSET_DIAG_ADDR, MPT_DIAG_MEM_CFG_BASE);
mpt_pio_write(mpt, MPT_OFFSET_DIAG_DATA, data);
pci_disable_io(mpt->dev, SYS_RES_IOPORT);
/*
* Re-enable the processor and clear the boot halt flag.
*/
@ -2138,6 +2173,7 @@ mpt_configure_ioc(struct mpt_softc *mpt)
MSG_IOC_FACTS_REPLY facts;
int try;
int needreset;
uint32_t max_chain_depth;
needreset = 0;
for (try = 0; try < MPT_MAX_TRYS; try++) {
@ -2166,23 +2202,65 @@ mpt_configure_ioc(struct mpt_softc *mpt)
mpt->mpt_global_credits = le16toh(facts.GlobalCredits);
mpt->request_frame_size = le16toh(facts.RequestFrameSize);
mpt->ioc_facts_flags = facts.Flags;
mpt_prt(mpt, "MPI Version=%d.%d.%d.%d\n",
le16toh(facts.MsgVersion) >> 8,
le16toh(facts.MsgVersion) & 0xFF,
le16toh(facts.HeaderVersion) >> 8,
le16toh(facts.HeaderVersion) & 0xFF);
/*
* Now that we know request frame size, we can calculate
* the actual (reasonable) segment limit for read/write I/O.
*
* This limit is constrained by:
*
* + The size of each area we allocate per command (and how
* many chain segments we can fit into it).
* + The total number of areas we've set up.
* + The actual chain depth the card will allow.
*
* The first area's segment count is limited by the I/O request
* at the head of it. We cannot allocate realistically more
* than MPT_MAX_REQUESTS areas. Therefore, to account for both
* conditions, we'll just start out with MPT_MAX_REQUESTS-2.
*
*/
max_chain_depth = facts.MaxChainDepth;
/* total number of request areas we (can) allocate */
mpt->max_seg_cnt = MPT_MAX_REQUESTS(mpt) - 2;
/* converted to the number of chain areas possible */
mpt->max_seg_cnt *= MPT_NRFM(mpt);
/* limited by the number of chain areas the card will support */
if (mpt->max_seg_cnt > max_chain_depth) {
mpt_lprt(mpt, MPT_PRT_DEBUG,
"chain depth limited to %u (from %u)\n",
max_chain_depth, mpt->max_seg_cnt);
mpt->max_seg_cnt = max_chain_depth;
}
/* converted to the number of simple sges in chain segments. */
mpt->max_seg_cnt *= (MPT_NSGL(mpt) - 1);
mpt_lprt(mpt, MPT_PRT_DEBUG,
"Maximum Segment Count: %u\n", mpt->max_seg_cnt);
mpt_lprt(mpt, MPT_PRT_DEBUG,
"MsgLength=%u IOCNumber = %d\n",
facts.MsgLength, facts.IOCNumber);
mpt_lprt(mpt, MPT_PRT_DEBUG,
"IOCFACTS: GlobalCredits=%d BlockSize=%u "
"Request Frame Size %u\n", mpt->mpt_global_credits,
facts.BlockSize * 8, mpt->request_frame_size * 8);
"IOCFACTS: GlobalCredits=%d BlockSize=%u bytes "
"Request Frame Size %u bytes Max Chain Depth %u\n",
mpt->mpt_global_credits, facts.BlockSize,
mpt->request_frame_size << 2, max_chain_depth);
mpt_lprt(mpt, MPT_PRT_DEBUG,
"IOCFACTS: Num Ports %d, FWImageSize %d, "
"Flags=%#x\n", facts.NumberOfPorts,
le32toh(facts.FWImageSize), facts.Flags);
if ((facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) != 0) {
struct mpt_map_info mi;
int error;
@ -2249,6 +2327,7 @@ mpt_configure_ioc(struct mpt_softc *mpt)
mpt->mpt_port_type = pfp.PortType;
mpt->mpt_proto_flags = pfp.ProtocolFlags;
if (pfp.PortType != MPI_PORTFACTS_PORTTYPE_SCSI &&
pfp.PortType != MPI_PORTFACTS_PORTTYPE_SAS &&
pfp.PortType != MPI_PORTFACTS_PORTTYPE_FC) {
mpt_prt(mpt, "Unsupported Port Type (%x)\n",
pfp.PortType);
@ -2260,10 +2339,16 @@ mpt_configure_ioc(struct mpt_softc *mpt)
}
if (pfp.PortType == MPI_PORTFACTS_PORTTYPE_FC) {
mpt->is_fc = 1;
mpt->is_sas = 0;
} else if (pfp.PortType == MPI_PORTFACTS_PORTTYPE_SAS) {
mpt->is_fc = 0;
mpt->is_sas = 1;
} else {
mpt->is_fc = 0;
mpt->is_sas = 0;
}
mpt->mpt_ini_id = pfp.PortSCSIID;
mpt->mpt_max_devices = pfp.MaxDevices;
if (mpt_enable_ioc(mpt) != 0) {
mpt_prt(mpt, "Unable to initialize IOC\n");
@ -2280,7 +2365,7 @@ mpt_configure_ioc(struct mpt_softc *mpt)
*/
mpt_read_config_info_ioc(mpt);
if (mpt->is_fc == 0) {
if (mpt->is_fc == 0 && mpt->is_sas == 0) {
if (mpt_read_config_info_spi(mpt)) {
return (EIO);
}
@ -2310,7 +2395,7 @@ mpt_enable_ioc(struct mpt_softc *mpt)
uint32_t pptr;
int val;
if (mpt_send_ioc_init(mpt, MPT_DB_INIT_HOST) != MPT_OK) {
if (mpt_send_ioc_init(mpt, MPI_WHOINIT_HOST_DRIVER) != MPT_OK) {
mpt_prt(mpt, "mpt_send_ioc_init failed\n");
return (EIO);
}
@ -2321,7 +2406,7 @@ mpt_enable_ioc(struct mpt_softc *mpt)
mpt_prt(mpt, "IOC failed to go to run state\n");
return (ENXIO);
}
mpt_lprt(mpt, MPT_PRT_DEBUG, "IOC now at RUNSTATE");
mpt_lprt(mpt, MPT_PRT_DEBUG, "IOC now at RUNSTATE\n");
/*
* Give it reply buffers
@ -2342,14 +2427,14 @@ mpt_enable_ioc(struct mpt_softc *mpt)
mpt_send_event_request(mpt, 1);
/*
* Now enable the port
* Enable the port
*/
if (mpt_send_port_enable(mpt, 0) != MPT_OK) {
mpt_prt(mpt, "failed to enable port 0\n");
return (ENXIO);
}
mpt_lprt(mpt, MPT_PRT_DEBUG, "enabled port 0\n");
return (0);
}

View File

@ -86,13 +86,21 @@
#include <sys/bus.h>
#include <sys/module.h>
#include <machine/bus.h>
#include <machine/clock.h>
#include <machine/cpu.h>
#include <machine/resource.h>
#include <sys/rman.h>
#if __FreeBSD_version < 500000
#include <pci/pcireg.h>
#include <pci/pcivar.h>
#else
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#endif
#include <machine/bus.h>
#include "opt_ddb.h"
/**************************** Register Definitions ****************************/
@ -247,6 +255,7 @@ struct req_entry {
bus_addr_t req_pbuf; /* Physical Address of Entry */
bus_addr_t sense_pbuf; /* Physical Address of sense data */
bus_dmamap_t dmap; /* DMA map for data buffer */
struct req_entry *chain; /* for SGE overallocations */
};
/**************************** Handler Registration ****************************/
@ -376,7 +385,8 @@ struct mpt_softc {
struct mtx mpt_lock;
#endif
uint32_t mpt_pers_mask;
uint32_t : 15,
uint32_t : 14,
is_sas : 1,
raid_mwce_set : 1,
getreqwaiter : 1,
shutdwn_raid : 1,
@ -397,6 +407,7 @@ struct mpt_softc {
uint16_t request_frame_size;
uint8_t mpt_max_devices;
uint8_t mpt_max_buses;
uint8_t ioc_facts_flags;
/*
* Port Facts
@ -486,6 +497,11 @@ struct mpt_softc {
uint8_t *request; /* KVA of Request memory */
bus_addr_t request_phys; /* BusADdr of request memory */
uint32_t max_seg_cnt; /* calculated after IOC facts */
/*
* Hardware management
*/
u_int reset_cnt;
/*
@ -658,11 +674,11 @@ mpt_pio_read(struct mpt_softc *mpt, int offset)
}
/*********************** Reply Frame/Request Management ***********************/
/* Max MPT Reply we are willing to accept (must be power of 2) */
#define MPT_REPLY_SIZE 128
#define MPT_REPLY_SIZE 256
#define MPT_MAX_REQUESTS(mpt) ((mpt)->is_fc ? 1024 : 256)
#define MPT_REQUEST_AREA 512
#define MPT_SENSE_SIZE 32 /* included in MPT_REQUEST_SIZE */
#define MPT_MAX_REQUESTS(mpt) 512
#define MPT_REQUEST_AREA 512
#define MPT_SENSE_SIZE 32 /* included in MPT_REQUEST_AREA */
#define MPT_REQ_MEM_SIZE(mpt) (MPT_MAX_REQUESTS(mpt) * MPT_REQUEST_AREA)
#define MPT_CONTEXT_CB_SHIFT (16)
@ -714,33 +730,25 @@ mpt_pop_reply_queue(struct mpt_softc *mpt)
void mpt_complete_request_chain(struct mpt_softc *mpt,
struct req_queue *chain, u_int iocstatus);
/************************** Scatter Gather Managment **************************/
/*
* We cannot tell prior to getting IOC facts how big the IOC's request
* area is. Because of this we cannot tell at compile time how many
* simple SG elements we can fit within an IOC request prior to having
* to put in a chain element.
*
* Experimentally we know that the Ultra4 parts have a 96 byte request
* element size and the Fibre Channel units have a 144 byte request
* element size. Therefore, if we have 512-32 (== 480) bytes of request
* area to play with, we have room for between 3 and 5 request sized
* regions- the first of which is the command plus a simple SG list,
* the rest of which are chained continuation SG lists. Given that the
* normal request we use is 48 bytes w/o the first SG element, we can
* assume we have 480-48 == 432 bytes to have simple SG elements and/or
* chain elements. If we assume 32 bit addressing, this works out to
* 54 SG or chain elements. If we assume 5 chain elements, then we have
* a maximum of 49 seperate actual SG segments.
*/
#define MPT_SGL_MAX 49
/* MPT_RQSL- size of request frame, in bytes */
#define MPT_RQSL(mpt) (mpt->request_frame_size << 2)
#define MPT_NSGL(mpt) (MPT_RQSL(mpt) / sizeof (SGE_SIMPLE32))
#define MPT_NSGL_FIRST(mpt) \
(((mpt->request_frame_size << 2) - \
sizeof (MSG_SCSI_IO_REQUEST) - \
sizeof (SGE_IO_UNION)) / sizeof (SGE_SIMPLE32))
/* MPT_NSGL- how many SG entries can fit in a request frame size */
#define MPT_NSGL(mpt) (MPT_RQSL(mpt) / sizeof (SGE_IO_UNION))
/* MPT_NRFM- how many request frames can fit in each request alloc we make */
#define MPT_NRFM(mpt) (MPT_REQUEST_AREA / MPT_RQSL(mpt))
/*
* MPT_NSGL_FIRST- # of SG elements that can fit after
* an I/O request but still within the request frame.
* Do this safely based upon SGE_IO_UNION.
*
* Note that the first element is *within* the SCSI request.
*/
#define MPT_NSGL_FIRST(mpt) \
((MPT_RQSL(mpt) - sizeof (MSG_SCSI_IO_REQUEST) + sizeof (SGE_IO_UNION)) / \
sizeof (SGE_IO_UNION))
/***************************** IOC Initialization *****************************/
int mpt_reset(struct mpt_softc *, int /*reinit*/);
@ -763,7 +771,8 @@ enum {
MPT_PRT_WARN,
MPT_PRT_INFO,
MPT_PRT_DEBUG,
MPT_PRT_TRACE
MPT_PRT_TRACE,
MPT_PRT_NONE=100
};
#define mpt_lprt(mpt, level, ...) \
@ -850,4 +859,5 @@ void mpt_req_state(mpt_req_state_t state);
void mpt_print_config_request(void *vmsg);
void mpt_print_request(void *vmsg);
void mpt_print_scsi_io_request(MSG_SCSI_IO_REQUEST *msg);
void mpt_dump_sgl(SGE_IO_UNION *se, int offset);
#endif /* _MPT_H_ */

View File

@ -350,11 +350,16 @@ mpt_timeout(void *arg)
static void
mpt_execute_req(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
{
request_t *req;
request_t *req, *trq;
char *mpt_off;
union ccb *ccb;
struct mpt_softc *mpt;
int seg, first_lim;
uint32_t flags, nxt_off;
bus_dmasync_op_t op;
MSG_SCSI_IO_REQUEST *mpt_req;
SGE_SIMPLE32 *se;
SGE_SIMPLE64 *se;
SGE_CHAIN64 *ce;
req = (request_t *)arg;
ccb = req->ccb;
@ -362,20 +367,30 @@ mpt_execute_req(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
mpt = ccb->ccb_h.ccb_mpt_ptr;
req = ccb->ccb_h.ccb_req_ptr;
mpt_req = req->req_vbuf;
mpt_off = req->req_vbuf;
if (error == 0 && nseg > MPT_SGL_MAX) {
if (error == 0 && ((uint32_t)nseg) >= mpt->max_seg_cnt) {
error = EFBIG;
}
bad:
if (error != 0) {
if (error != EFBIG)
/* if (error != EFBIG) */
mpt_prt(mpt, "bus_dmamap_load returned %d\n", error);
if (ccb->ccb_h.status == CAM_REQ_INPROG) {
xpt_freeze_devq(ccb->ccb_h.path, 1);
ccb->ccb_h.status = CAM_DEV_QFRZN;
if (error == EFBIG)
if (error == EFBIG) {
ccb->ccb_h.status |= CAM_REQ_TOO_BIG;
else
} else if (error == ENOMEM) {
if (mpt->outofbeer == 0) {
mpt->outofbeer = 1;
xpt_freeze_simq(mpt->sim, 1);
mpt_lprt(mpt, MPT_PRT_DEBUG,
"FREEZEQ\n");
}
ccb->ccb_h.status |= CAM_REQUEUE_REQ;
} else
ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
}
ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
@ -385,136 +400,234 @@ mpt_execute_req(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
MPTLOCK_2_CAMLOCK(mpt);
return;
}
if (nseg > MPT_NSGL_FIRST(mpt)) {
int i, nleft = nseg;
uint32_t flags;
bus_dmasync_op_t op;
SGE_CHAIN32 *ce;
mpt_req->DataLength = ccb->csio.dxfer_len;
flags = MPI_SGE_FLAGS_SIMPLE_ELEMENT;
if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)
flags |= MPI_SGE_FLAGS_HOST_TO_IOC;
/*
* No data to transfer?
* Just make a single simple SGL with zero length.
*/
se = (SGE_SIMPLE32 *) &mpt_req->SGL;
for (i = 0; i < MPT_NSGL_FIRST(mpt) - 1; i++, se++, dm_segs++) {
uint32_t tf;
if (mpt->verbose >= MPT_PRT_DEBUG) {
int tidx = ((char *)&mpt_req->SGL) - mpt_off;
memset(&mpt_off[tidx], 0xff, MPT_REQUEST_AREA - tidx);
}
bzero(se, sizeof (*se));
se->Address = dm_segs->ds_addr;
MPI_pSGE_SET_LENGTH(se, dm_segs->ds_len);
tf = flags;
if (i == MPT_NSGL_FIRST(mpt) - 2) {
tf |= MPI_SGE_FLAGS_LAST_ELEMENT;
}
MPI_pSGE_SET_FLAGS(se, tf);
nleft -= 1;
}
/*
* Tell the IOC where to find the first chain element
*/
mpt_req->ChainOffset = ((char *)se - (char *)mpt_req) >> 2;
/*
* Until we're finished with all segments...
*/
while (nleft) {
int ntodo;
/*
* Construct the chain element that point to the
* next segment.
*/
ce = (SGE_CHAIN32 *) se++;
if (nleft > MPT_NSGL(mpt)) {
ntodo = MPT_NSGL(mpt) - 1;
ce->NextChainOffset = (MPT_RQSL(mpt) -
sizeof (SGE_SIMPLE32)) >> 2;
ce->Length = MPT_NSGL(mpt) *
sizeof (SGE_SIMPLE32);
} else {
ntodo = nleft;
ce->NextChainOffset = 0;
ce->Length = ntodo * sizeof (SGE_SIMPLE32);
}
ce->Address = req->req_pbuf +
((char *)se - (char *)mpt_req);
ce->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT;
for (i = 0; i < ntodo; i++, se++, dm_segs++) {
uint32_t tf;
bzero(se, sizeof (*se));
se->Address = dm_segs->ds_addr;
MPI_pSGE_SET_LENGTH(se, dm_segs->ds_len);
tf = flags;
if (i == ntodo - 1) {
tf |= MPI_SGE_FLAGS_LAST_ELEMENT;
if (ce->NextChainOffset == 0) {
tf |=
MPI_SGE_FLAGS_END_OF_LIST |
MPI_SGE_FLAGS_END_OF_BUFFER;
}
}
MPI_pSGE_SET_FLAGS(se, tf);
nleft -= 1;
}
}
if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
op = BUS_DMASYNC_PREREAD;
else
op = BUS_DMASYNC_PREWRITE;
if (!(ccb->ccb_h.flags & (CAM_SG_LIST_PHYS|CAM_DATA_PHYS))) {
bus_dmamap_sync(mpt->buffer_dmat, req->dmap, op);
}
} else if (nseg > 0) {
int i;
uint32_t flags;
bus_dmasync_op_t op;
mpt_req->DataLength = ccb->csio.dxfer_len;
flags = MPI_SGE_FLAGS_SIMPLE_ELEMENT;
if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)
flags |= MPI_SGE_FLAGS_HOST_TO_IOC;
/* Copy the segments into our SG list */
se = (SGE_SIMPLE32 *) &mpt_req->SGL;
for (i = 0; i < nseg; i++, se++, dm_segs++) {
uint32_t tf;
bzero(se, sizeof (*se));
se->Address = dm_segs->ds_addr;
MPI_pSGE_SET_LENGTH(se, dm_segs->ds_len);
tf = flags;
if (i == nseg - 1) {
tf |=
MPI_SGE_FLAGS_LAST_ELEMENT |
MPI_SGE_FLAGS_END_OF_BUFFER |
MPI_SGE_FLAGS_END_OF_LIST;
}
MPI_pSGE_SET_FLAGS(se, tf);
}
if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
op = BUS_DMASYNC_PREREAD;
else
op = BUS_DMASYNC_PREWRITE;
if (!(ccb->ccb_h.flags & (CAM_SG_LIST_PHYS|CAM_DATA_PHYS))) {
bus_dmamap_sync(mpt->buffer_dmat, req->dmap, op);
}
} else {
se = (SGE_SIMPLE32 *) &mpt_req->SGL;
/*
* No data to transfer so we just make a single simple SGL
* with zero length.
*/
MPI_pSGE_SET_FLAGS(se,
if (nseg == 0) {
SGE_SIMPLE32 *se1 = (SGE_SIMPLE32 *) &mpt_req->SGL;
MPI_pSGE_SET_FLAGS(se1,
(MPI_SGE_FLAGS_LAST_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER |
MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_END_OF_LIST));
goto out;
}
mpt_req->DataLength = ccb->csio.dxfer_len;
flags = MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_64_BIT_ADDRESSING;
if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)
flags |= MPI_SGE_FLAGS_HOST_TO_IOC;
if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
op = BUS_DMASYNC_PREREAD;
} else {
op = BUS_DMASYNC_PREWRITE;
}
if (!(ccb->ccb_h.flags & (CAM_SG_LIST_PHYS|CAM_DATA_PHYS))) {
bus_dmamap_sync(mpt->buffer_dmat, req->dmap, op);
}
/*
* Okay, fill in what we can at the end of the command frame.
* If we have up to MPT_NSGL_FIRST, we can fit them all into
* the command frame.
*
* Otherwise, we fill up through MPT_NSGL_FIRST less one
* SIMPLE64 pointers and start doing CHAIN64 entries after
* that.
*/
if (nseg < MPT_NSGL_FIRST(mpt)) {
first_lim = nseg;
} else {
/*
* Leave room for CHAIN element
*/
first_lim = MPT_NSGL_FIRST(mpt) - 1;
}
se = (SGE_SIMPLE64 *) &mpt_req->SGL;
for (seg = 0; seg < first_lim; seg++, se++, dm_segs++) {
uint32_t tf;
bzero(se, sizeof (*se));
se->Address.Low = dm_segs->ds_addr;
if (sizeof(bus_addr_t) > 4) {
se->Address.High = ((uint64_t) dm_segs->ds_addr) >> 32;
}
MPI_pSGE_SET_LENGTH(se, dm_segs->ds_len);
tf = flags;
if (seg == first_lim - 1) {
tf |= MPI_SGE_FLAGS_LAST_ELEMENT;
}
if (seg == nseg - 1) {
tf |= MPI_SGE_FLAGS_END_OF_LIST |
MPI_SGE_FLAGS_END_OF_BUFFER;
}
MPI_pSGE_SET_FLAGS(se, tf);
}
if (seg == nseg) {
goto out;
}
/*
* Tell the IOC where to find the first chain element.
*/
mpt_req->ChainOffset = ((char *)se - (char *)mpt_req) >> 2;
nxt_off = MPT_RQSL(mpt);
trq = req;
/*
* Make up the rest of the data segments out of a chain element
* (contiained in the current request frame) which points to
* SIMPLE64 elements in the next request frame, possibly ending
* with *another* chain element (if there's more).
*/
while (seg < nseg) {
int this_seg_lim;
uint32_t tf, cur_off;
bus_addr_t chain_list_addr;
/*
* Point to the chain descriptor. Note that the chain
* descriptor is at the end of the *previous* list (whether
* chain or simple).
*/
ce = (SGE_CHAIN64 *) se;
/*
* Before we change our current pointer, make sure we won't
* overflow the request area with this frame. Note that we
* test against 'greater than' here as it's okay in this case
* to have next offset be just outside the request area.
*/
if ((nxt_off + MPT_RQSL(mpt)) > MPT_REQUEST_AREA) {
nxt_off = MPT_REQUEST_AREA;
goto next_chain;
}
/*
* Set our SGE element pointer to the beginning of the chain
* list and update our next chain list offset.
*/
se = (SGE_SIMPLE64 *) &mpt_off[nxt_off];
cur_off = nxt_off;
nxt_off += MPT_RQSL(mpt);
/*
* Now initialized the chain descriptor.
*/
bzero(ce, sizeof (SGE_CHAIN64));
/*
* Get the physical address of the chain list.
*/
chain_list_addr = trq->req_pbuf;
chain_list_addr += cur_off;
if (sizeof (bus_addr_t) > 4) {
ce->Address.High =
(uint32_t) ((uint64_t)chain_list_addr >> 32);
}
ce->Address.Low = (uint32_t) chain_list_addr;
ce->Flags = MPI_SGE_FLAGS_CHAIN_ELEMENT |
MPI_SGE_FLAGS_64_BIT_ADDRESSING;
/*
* If we have more than a frame's worth of segments left,
* set up the chain list to have the last element be another
* chain descriptor.
*/
if ((nseg - seg) > MPT_NSGL(mpt)) {
this_seg_lim = seg + MPT_NSGL(mpt) - 1;
/*
* The length of the chain is the length in bytes of the
* number of segments plus the next chain element.
*
* The next chain descriptor offset is the length,
* in words, of the number of segments.
*/
ce->Length = (this_seg_lim - seg) *
sizeof (SGE_SIMPLE64);
ce->NextChainOffset = ce->Length >> 2;
ce->Length += sizeof (SGE_CHAIN64);
} else {
this_seg_lim = nseg;
ce->Length = (this_seg_lim - seg) *
sizeof (SGE_SIMPLE64);
}
/*
* Fill in the chain list SGE elements with our segment data.
*
* If we're the last element in this chain list, set the last
* element flag. If we're the completely last element period,
* set the end of list and end of buffer flags.
*/
while (seg < this_seg_lim) {
bzero(se, sizeof (*se));
se->Address.Low = dm_segs->ds_addr;
if (sizeof (bus_addr_t) > 4) {
se->Address.High =
((uint64_t)dm_segs->ds_addr) >> 32;
}
MPI_pSGE_SET_LENGTH(se, dm_segs->ds_len);
tf = flags;
if (seg == this_seg_lim - 1) {
tf |= MPI_SGE_FLAGS_LAST_ELEMENT;
}
if (seg == nseg - 1) {
tf |= MPI_SGE_FLAGS_END_OF_LIST |
MPI_SGE_FLAGS_END_OF_BUFFER;
}
MPI_pSGE_SET_FLAGS(se, tf);
se++;
seg++;
dm_segs++;
}
next_chain:
/*
* If we have more segments to do and we've used up all of
* the space in a request area, go allocate another one
* and chain to that.
*/
if (seg < nseg && nxt_off >= MPT_REQUEST_AREA) {
request_t *nrq = mpt_get_request(mpt, FALSE);
if (nrq == NULL) {
error = ENOMEM;
goto bad;
}
/*
* Append the new request area on the tail of our list.
*/
if ((trq = req->chain) == NULL) {
req->chain = nrq;
} else {
while (trq->chain != NULL) {
trq = trq->chain;
}
trq->chain = nrq;
}
trq = nrq;
mpt_off = trq->req_vbuf;
mpt_req = trq->req_vbuf;
if (mpt->verbose >= MPT_PRT_DEBUG) {
memset(mpt_off, 0xff, MPT_REQUEST_AREA);
}
nxt_off = 0;
}
}
out:
/*
* Last time we need to check if this CCB needs to be aborted.
*/
@ -537,8 +650,14 @@ mpt_execute_req(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
} else {
callout_handle_init(&ccb->ccb_h.timeout_ch);
}
if (mpt->verbose >= MPT_PRT_DEBUG)
mpt_print_scsi_io_request(mpt_req);
if (mpt->verbose >= MPT_PRT_DEBUG) {
int nc = 0;
mpt_print_scsi_io_request(req->req_vbuf);
for (trq = req->chain; trq; trq = trq->chain) {
printf(" Additional Chain Area %d\n", nc++);
mpt_dump_sgl(trq->req_vbuf, 0);
}
}
mpt_send_cmd(mpt, req);
MPTLOCK_2_CAMLOCK(mpt);
}
@ -578,6 +697,7 @@ mpt_start(struct cam_sim *sim, union ccb *ccb)
if (raid_passthru) {
status = mpt_raid_quiesce_disk(mpt, mpt->raid_disks + ccb->ccb_h.target_id,
request_t *req)
}
#endif
/*
@ -646,7 +766,7 @@ mpt_start(struct cam_sim *sim, union ccb *ccb)
mpt_req->Control |= MPI_SCSIIO_CONTROL_UNTAGGED;
}
if (mpt->is_fc == 0) {
if (mpt->is_fc == 0 && mpt->is_sas == 0) {
if (ccb->ccb_h.flags & CAM_DIS_DISCONNECT) {
mpt_req->Control |= MPI_SCSIIO_CONTROL_NO_DISCONNECT;
}
@ -716,9 +836,7 @@ mpt_start(struct cam_sim *sim, union ccb *ccb)
} else {
/* Just use the segments provided */
segs = (struct bus_dma_segment *)csio->data_ptr;
mpt_execute_req(req, segs, csio->sglist_cnt,
(csio->sglist_cnt < MPT_SGL_MAX)?
0 : EFBIG);
mpt_execute_req(req, segs, csio->sglist_cnt, 0);
}
}
} else {
@ -771,6 +889,8 @@ static int
mpt_cam_event(struct mpt_softc *mpt, request_t *req,
MSG_EVENT_NOTIFY_REPLY *msg)
{
mpt_lprt(mpt, MPT_PRT_ALWAYS, "mpt_cam_event: 0x%x\n",
msg->Event & 0xFF);
switch(msg->Event & 0xFF) {
case MPI_EVENT_UNIT_ATTENTION:
mpt_prt(mpt, "Bus: 0x%02x TargetID: 0x%02x\n",
@ -875,6 +995,17 @@ mpt_cam_event(struct mpt_softc *mpt, request_t *req,
mpt_prt(mpt, "FC Logout Port: %d N_PortID: %02x\n",
(msg->Data[1] >> 8) & 0xff, msg->Data[0]);
break;
case MPI_EVENT_EVENT_CHANGE:
mpt_lprt(mpt, MPT_PRT_DEBUG,
"mpt_cam_event: MPI_EVENT_EVENT_CHANGE\n");
break;
case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
/*
* Devices are attachin'.....
*/
mpt_prt(mpt,
"mpt_cam_event: MPI_EVENT_SAS_DEVICE_STATUS_CHANGE\n");
break;
default:
return (/*handled*/0);
}
@ -1282,7 +1413,7 @@ mpt_action(struct cam_sim *sim, union ccb *ccb)
xpt_done(ccb);
break;
}
if (mpt->is_fc == 0) {
if (mpt->is_fc == 0 && mpt->is_sas == 0) {
uint8_t dval = 0;
u_int period = 0, offset = 0;
#ifndef CAM_NEW_TRAN_CODE
@ -1413,6 +1544,30 @@ mpt_prt(mpt, "Set sync Failed!\n");
fc->valid = CTS_FC_VALID_SPEED;
fc->bitrate = 100000; /* XXX: Need for 2Gb/s */
/* XXX: need a port database for each target */
#endif
} else if (mpt->is_sas) {
#ifndef CAM_NEW_TRAN_CODE
cts->flags = CCB_TRANS_TAG_ENB | CCB_TRANS_DISC_ENB;
cts->valid = CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID;
/*
* How do you measure the width of a high
* speed serial bus? Well, in bytes.
*
* Offset and period make no sense, though, so we set
* (above) a 'base' transfer speed to be gigabit.
*/
cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
#else
struct ccb_trans_settings_sas *sas =
&cts->xport_specific.sas;
cts->protocol = PROTO_SCSI;
cts->protocol_version = SCSI_REV_3;
cts->transport = XPORT_SAS;
cts->transport_version = 0;
sas->valid = CTS_SAS_VALID_SPEED;
sas->bitrate = 300000; /* XXX: Default 3Gbps */
#endif
} else {
#ifdef CAM_NEW_TRAN_CODE
@ -1572,17 +1727,26 @@ mpt_prt(mpt, "Set sync Failed!\n");
cpi->hba_inquiry = PI_TAG_ABLE;
if (mpt->is_fc) {
cpi->base_transfer_speed = 100000;
} else if (mpt->is_sas) {
cpi->base_transfer_speed = 300000;
} else {
cpi->base_transfer_speed = 3300;
cpi->hba_inquiry |=
PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
}
} else if (mpt->is_fc) {
/* XXX SHOULD BE BASED UPON IOC FACTS XXX */
cpi->max_target = 255;
cpi->hba_misc = PIM_NOBUSRESET;
cpi->initiator_id = cpi->max_target + 1;
cpi->base_transfer_speed = 100000;
cpi->hba_inquiry = PI_TAG_ABLE;
} else if (mpt->is_sas) {
cpi->max_target = 63; /* XXX */
cpi->hba_misc = PIM_NOBUSRESET;
cpi->initiator_id = cpi->max_target;
cpi->base_transfer_speed = 300000;
cpi->hba_inquiry = PI_TAG_ABLE;
} else {
cpi->initiator_id = mpt->mpt_ini_id;
cpi->base_transfer_speed = 3300;

View File

@ -172,8 +172,6 @@ static const struct Error_Map IOC_SCSITMType[] = {
{ -1, 0 },
};
static void mpt_dump_sgl(SGE_IO_UNION *sgl);
static char *
mpt_ioc_status(int code)
{
@ -527,7 +525,12 @@ mpt_print_scsi_io_request(MSG_SCSI_IO_REQUEST *orig_msg)
for (i = 0; i < msg->CDBLength; i++)
printf("%02x ", msg->CDB[i]);
printf("\n");
mpt_dump_sgl(&orig_msg->SGL);
if ((msg->Control & MPI_SCSIIO_CONTROL_DATADIRECTION_MASK) !=
MPI_SCSIIO_CONTROL_NODATATRANSFER ) {
mpt_dump_sgl(&orig_msg->SGL,
((char *)&orig_msg->SGL)-(char *)orig_msg);
}
}
static void
@ -625,35 +628,69 @@ mpt_req_state(mpt_req_state_t state)
"REQ_STATE", state, NULL, 80);
}
static void
mpt_dump_sgl(SGE_IO_UNION *su)
#define LAST_SGE ( \
MPI_SGE_FLAGS_END_OF_LIST | \
MPI_SGE_FLAGS_END_OF_BUFFER| \
MPI_SGE_FLAGS_LAST_ELEMENT)
void
mpt_dump_sgl(SGE_IO_UNION *su, int offset)
{
SGE_SIMPLE32 *se = (SGE_SIMPLE32 *) su;
int iCount, flags;
const char allfox[4] = { 0xff, 0xff, 0xff, 0xff };
void *nxtaddr = se;
void *lim;
int flags;
/*
* Can't be any bigger than this.
*/
lim = &((char *)se)[MPT_REQUEST_AREA - offset];
iCount = MPT_SGL_MAX;
do {
int iprt;
printf("\t");
if (memcmp(se, allfox, 4) == 0) {
uint32_t *nxt = (uint32_t *)se;
printf("PAD %p\n", se);
nxtaddr = nxt + 1;
se = nxtaddr;
flags = 0;
continue;
}
nxtaddr = se + 1;
flags = MPI_SGE_GET_FLAGS(se->FlagsLength);
switch (flags & MPI_SGE_FLAGS_ELEMENT_MASK) {
case MPI_SGE_FLAGS_SIMPLE_ELEMENT:
{
printf("SE32 %p: Addr=0x%0x FlagsLength=0x%0x\n",
se, se->Address, se->FlagsLength);
if (flags & MPI_SGE_FLAGS_64_BIT_ADDRESSING) {
SGE_SIMPLE64 *se64 = (SGE_SIMPLE64 *)se;
printf("SE64 %p: Addr=0x%08x%08x FlagsLength"
"=0x%0x\n", se64, se64->Address.High,
se64->Address.Low, se64->FlagsLength);
nxtaddr = se64 + 1;
} else {
printf("SE32 %p: Addr=0x%0x FlagsLength=0x%0x"
"\n", se, se->Address, se->FlagsLength);
}
printf(" ");
break;
}
case MPI_SGE_FLAGS_CHAIN_ELEMENT:
{
SGE_CHAIN32 *ce = (SGE_CHAIN32 *) se;
printf("CE32 %p: Addr=0x%0x NxtChnO=0x%x Flgs=0x%x "
"Len=0x%0x\n", ce, ce->Address, ce->NextChainOffset,
ce->Flags, ce->Length);
if (flags & MPI_SGE_FLAGS_64_BIT_ADDRESSING) {
SGE_CHAIN64 *ce64 = (SGE_CHAIN64 *) se;
printf("CE64 %p: Addr=0x%08x%08x NxtChnO=0x%x "
"Flgs=0x%x Len=0x%0x\n", ce64,
ce64->Address.High, ce64->Address.Low,
ce64->NextChainOffset,
ce64->Flags, ce64->Length);
nxtaddr = ce64 + 1;
} else {
SGE_CHAIN32 *ce = (SGE_CHAIN32 *) se;
printf("CE32 %p: Addr=0x%0x NxtChnO=0x%x "
" Flgs=0x%x Len=0x%0x\n", ce, ce->Address,
ce->NextChainOffset, ce->Flags, ce->Length);
}
flags = 0;
break;
}
case MPI_SGE_FLAGS_TRANSACTION_ELEMENT:
printf("TE32 @ %p\n", se);
flags = 0;
@ -678,9 +715,11 @@ mpt_dump_sgl(SGE_IO_UNION *su)
#undef MPT_PRINT_FLAG
if (iprt)
printf("\n");
se++;
iCount -= 1;
} while ((flags & MPI_SGE_FLAGS_END_OF_LIST) == 0 && iCount != 0);
se = nxtaddr;
if ((flags & LAST_SGE) == LAST_SGE) {
break;
}
} while ((flags & MPI_SGE_FLAGS_END_OF_LIST) == 0 && nxtaddr < lim);
}
void

View File

@ -69,13 +69,6 @@ __FBSDID("$FreeBSD$");
#include <dev/mpt/mpt_cam.h>
#include <dev/mpt/mpt_raid.h>
#if __FreeBSD_version < 500000
#include <pci/pcireg.h>
#include <pci/pcivar.h>
#else
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#endif
#ifndef PCI_VENDOR_LSI
#define PCI_VENDOR_LSI 0x1000
@ -105,12 +98,43 @@ __FBSDID("$FreeBSD$");
#define PCI_PRODUCT_LSI_1030 0x0030
#endif
#ifndef PCI_PRODUCT_LSI_SAS1064
#define PCI_PRODUCT_LSI_SAS1064 0x0050
#endif
#ifndef PCI_PRODUCT_LSI_SAS1064A
#define PCI_PRODUCT_LSI_SAS1064A 0x005C
#endif
#ifndef PCI_PRODUCT_LSI_SAS1064E
#define PCI_PRODUCT_LSI_SAS1064E 0x0056
#endif
#ifndef PCI_PRODUCT_LSI_SAS1066
#define PCI_PRODUCT_LSI_SAS1066 0x005E
#endif
#ifndef PCI_PRODUCT_LSI_SAS1066E
#define PCI_PRODUCT_LSI_SAS1066E 0x005A
#endif
#ifndef PCI_PRODUCT_LSI_SAS1068
#define PCI_PRODUCT_LSI_SAS1068 0x0054
#endif
#ifndef PCI_PRODUCT_LSI_SAS1068E
#define PCI_PRODUCT_LSI_SAS1068E 0x0058
#endif
#ifndef PCI_PRODUCT_LSI_SAS1078
#define PCI_PRODUCT_LSI_SAS1078 0x0060
#endif
#ifndef PCIM_CMD_SERRESPEN
#define PCIM_CMD_SERRESPEN 0x0100
#endif
#define MPT_IO_BAR 0
#define MPT_MEM_BAR 1
@ -167,6 +191,16 @@ mpt_pci_probe(device_t dev)
case PCI_PRODUCT_LSI_1030:
desc = "LSILogic 1030 Ultra4 Adapter";
break;
case PCI_PRODUCT_LSI_SAS1064:
case PCI_PRODUCT_LSI_SAS1064A:
case PCI_PRODUCT_LSI_SAS1064E:
case PCI_PRODUCT_LSI_SAS1066:
case PCI_PRODUCT_LSI_SAS1066E:
case PCI_PRODUCT_LSI_SAS1068:
case PCI_PRODUCT_LSI_SAS1068E:
case PCI_PRODUCT_LSI_SAS1078:
desc = "LSILogic SAS Adapter";
break;
default:
return (ENXIO);
}
@ -268,6 +302,16 @@ mpt_pci_attach(device_t dev)
case PCI_PRODUCT_LSI_FC929:
mpt->is_fc = 1;
break;
case PCI_PRODUCT_LSI_SAS1064:
case PCI_PRODUCT_LSI_SAS1064A:
case PCI_PRODUCT_LSI_SAS1064E:
case PCI_PRODUCT_LSI_SAS1066:
case PCI_PRODUCT_LSI_SAS1066E:
case PCI_PRODUCT_LSI_SAS1068:
case PCI_PRODUCT_LSI_SAS1068E:
case PCI_PRODUCT_LSI_SAS1078:
mpt->is_sas = 1;
break;
default:
break;
}
@ -276,10 +320,13 @@ mpt_pci_attach(device_t dev)
mpt->raid_resync_rate = MPT_RAID_RESYNC_RATE_DEFAULT;
mpt->raid_mwce_setting = MPT_RAID_MWCE_DEFAULT;
mpt->raid_queue_depth = MPT_RAID_QUEUE_DEPTH_DEFAULT;
mpt->verbose = MPT_PRT_NONE;
mpt_set_options(mpt);
mpt->verbose = MPT_PRT_INFO;
mpt->verbose += (bootverbose != 0)? 1 : 0;
if (mpt->verbose == MPT_PRT_NONE) {
mpt->verbose = MPT_PRT_WARN;
/* Print INFO level (if any) if bootverbose is set */
mpt->verbose += (bootverbose != 0)? 1 : 0;
}
/* Make sure memory access decoders are enabled */
cmd = pci_read_config(dev, PCIR_COMMAND, 2);
if ((cmd & PCIM_CMD_MEMEN) == 0) {
@ -313,7 +360,8 @@ mpt_pci_attach(device_t dev)
/*
* Set up register access. PIO mode is required for
* certain reset operations.
* certain reset operations (but must be disabled for
* some cards otherwise).
*/
mpt->pci_pio_rid = PCIR_BAR(MPT_IO_BAR);
mpt->pci_pio_reg = bus_alloc_resource(dev, SYS_RES_IOPORT,
@ -331,6 +379,10 @@ mpt_pci_attach(device_t dev)
&mpt->pci_mem_rid, 0, ~0, 0, RF_ACTIVE);
if (mpt->pci_reg == NULL) {
device_printf(dev, "Unable to memory map registers.\n");
if (mpt->is_sas) {
device_printf(dev, "Giving Up.\n");
goto bad;
}
device_printf(dev, "Falling back to PIO mode.\n");
mpt->pci_st = mpt->pci_pio_st;
mpt->pci_sh = mpt->pci_pio_sh;
@ -384,8 +436,14 @@ mpt_pci_attach(device_t dev)
mpt_read_config_regs(mpt);
/*
* Disable PIO until we need it
*/
pci_disable_io(dev, SYS_RES_IOPORT);
/* Initialize the hardware */
if (mpt->disabled == 0) {
MPT_LOCK(mpt);
if (mpt_attach(mpt) != 0) {
MPT_UNLOCK(mpt);
@ -497,7 +555,7 @@ mpt_pci_shutdown(device_t dev)
static int
mpt_dma_mem_alloc(struct mpt_softc *mpt)
{
int i, error;
int i, error, nsegs;
uint8_t *vptr;
uint32_t pptr, end;
size_t len;
@ -526,13 +584,13 @@ mpt_dma_mem_alloc(struct mpt_softc *mpt)
#endif
/*
* Create a parent dma tag for this device
* Create a parent dma tag for this device.
*
* Align at byte boundaries, limit to 32-bit addressing
* (The chip supports 64-bit addressing, but this driver doesn't)
* Align at byte boundaries, limit to 32-bit addressing for
* request/reply queues.
*/
if (mpt_dma_tag_create(mpt, /*parent*/NULL, /*alignment*/1,
/*boundary*/0, /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
/*boundary*/0, /*lowaddr*/BUS_SPACE_MAXADDR,
/*highaddr*/BUS_SPACE_MAXADDR, /*filter*/NULL, /*filterarg*/NULL,
/*maxsize*/BUS_SPACE_MAXSIZE_32BIT,
/*nsegments*/BUS_SPACE_MAXSIZE_32BIT,
@ -543,9 +601,9 @@ mpt_dma_mem_alloc(struct mpt_softc *mpt)
}
/* Create a child tag for reply buffers */
if (mpt_dma_tag_create(mpt, mpt->parent_dmat, PAGE_SIZE,
0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR,
NULL, NULL, PAGE_SIZE, 1, BUS_SPACE_MAXSIZE_32BIT, 0,
if (mpt_dma_tag_create(mpt, mpt->parent_dmat, 2 * PAGE_SIZE,
0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
NULL, NULL, 2 * PAGE_SIZE, 1, BUS_SPACE_MAXSIZE_32BIT, 0,
&mpt->reply_dmat) != 0) {
device_printf(dev, "cannot create a dma tag for replies\n");
return (1);
@ -554,8 +612,9 @@ mpt_dma_mem_alloc(struct mpt_softc *mpt)
/* Allocate some DMA accessable memory for replies */
if (bus_dmamem_alloc(mpt->reply_dmat, (void **)&mpt->reply,
BUS_DMA_NOWAIT, &mpt->reply_dmap) != 0) {
device_printf(dev, "cannot allocate %lu bytes of reply memory\n",
(u_long)PAGE_SIZE);
device_printf(dev,
"cannot allocate %lu bytes of reply memory\n",
(u_long) (2 * PAGE_SIZE));
return (1);
}
@ -564,7 +623,7 @@ mpt_dma_mem_alloc(struct mpt_softc *mpt)
/* Load and lock it into "bus space" */
bus_dmamap_load(mpt->reply_dmat, mpt->reply_dmap, mpt->reply,
PAGE_SIZE, mpt_map_rquest, &mi, 0);
2 * PAGE_SIZE, mpt_map_rquest, &mi, 0);
if (mi.error) {
device_printf(dev,
@ -574,9 +633,16 @@ mpt_dma_mem_alloc(struct mpt_softc *mpt)
mpt->reply_phys = mi.phys;
/* Create a child tag for data buffers */
/*
* XXX: we should say that nsegs is 'unrestricted, but that
* XXX: tickles a horrible bug in the busdma code. Instead,
* XXX: we'll derive a reasonable segment limit from MAXPHYS
*/
nsegs = (MAXPHYS / PAGE_SIZE) + 1;
if (mpt_dma_tag_create(mpt, mpt->parent_dmat, 1,
0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR,
NULL, NULL, MAXBSIZE, MPT_SGL_MAX, BUS_SPACE_MAXSIZE_32BIT, 0,
NULL, NULL, MAXBSIZE, nsegs, BUS_SPACE_MAXSIZE_32BIT, 0,
&mpt->buffer_dmat) != 0) {
device_printf(dev,
"cannot create a dma tag for data buffers\n");
@ -585,7 +651,7 @@ mpt_dma_mem_alloc(struct mpt_softc *mpt)
/* Create a child tag for request buffers */
if (mpt_dma_tag_create(mpt, mpt->parent_dmat, PAGE_SIZE,
0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR,
0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
NULL, NULL, MPT_REQ_MEM_SIZE(mpt), 1, BUS_SPACE_MAXSIZE_32BIT, 0,
&mpt->request_dmat) != 0) {
device_printf(dev, "cannot create a dma tag for requests\n");