Rewrite the DMA code paths from being an impenitrable maze of special cases
to a much saner and simplier unified code path. Along the way, fix various CAM nits and bugs so that the passthrough works correctly for all cases.
This commit is contained in:
parent
21e10ad46a
commit
281017a577
@ -140,9 +140,9 @@ static int amr_mapcmd(struct amr_command *ac);
|
||||
static void amr_unmapcmd(struct amr_command *ac);
|
||||
static int amr_start(struct amr_command *ac);
|
||||
static void amr_complete(void *context, int pending);
|
||||
static void amr_setup_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error);
|
||||
static void amr_setup_dma64map(void *arg, bus_dma_segment_t *segs, int nsegments, int error);
|
||||
static void amr_setup_data_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error);
|
||||
static void amr_setup_sg(void *arg, bus_dma_segment_t *segs, int nsegments, int error);
|
||||
static void amr_setup_data(void *arg, bus_dma_segment_t *segs, int nsegments, int error);
|
||||
static void amr_setup_ccb(void *arg, bus_dma_segment_t *segs, int nsegments, int error);
|
||||
|
||||
/*
|
||||
* Status monitoring
|
||||
@ -572,9 +572,6 @@ amr_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag,
|
||||
|
||||
adapter = (ali.ui.fcs.adapno) ^ 'm' << 8;
|
||||
|
||||
ap = malloc(sizeof(struct amr_passthrough),
|
||||
M_AMR, M_WAITOK | M_ZERO);
|
||||
|
||||
mb = (void *)&ali.mbox[0];
|
||||
|
||||
if ((ali.mbox[0] == FC_DEL_LOGDRV && ali.mbox[2] == OP_DEL_LOGDRV) || /* delete */
|
||||
@ -587,6 +584,12 @@ amr_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag,
|
||||
}
|
||||
|
||||
if (ali.mbox[0] == AMR_CMD_PASS) {
|
||||
mtx_lock(&sc->amr_list_lock);
|
||||
while ((ac = amr_alloccmd(sc)) == NULL)
|
||||
msleep(sc, &sc->amr_list_lock, PPAUSE, "amrioc", hz);
|
||||
mtx_unlock(&sc->amr_list_lock);
|
||||
ap = &ac->ac_ccb->ccb_pthru;
|
||||
|
||||
error = copyin((void *)(uintptr_t)mb->mb_physaddr, ap,
|
||||
sizeof(struct amr_passthrough));
|
||||
if (error)
|
||||
@ -603,21 +606,16 @@ amr_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag,
|
||||
break;
|
||||
}
|
||||
|
||||
mtx_lock(&sc->amr_list_lock);
|
||||
while ((ac = amr_alloccmd(sc)) == NULL)
|
||||
msleep(sc, &sc->amr_list_lock, PPAUSE, "amrioc", hz);
|
||||
|
||||
ac_flags = AMR_CMD_DATAIN|AMR_CMD_DATAOUT|AMR_CMD_CCB_DATAIN|AMR_CMD_CCB_DATAOUT;
|
||||
ac_flags = AMR_CMD_DATAIN|AMR_CMD_DATAOUT|AMR_CMD_CCB;
|
||||
bzero(&ac->ac_mailbox, sizeof(ac->ac_mailbox));
|
||||
ac->ac_mailbox.mb_command = AMR_CMD_PASS;
|
||||
ac->ac_flags = ac_flags;
|
||||
|
||||
ac->ac_data = ap;
|
||||
ac->ac_length = sizeof(struct amr_passthrough);
|
||||
ac->ac_ccb_data = dp;
|
||||
ac->ac_ccb_length = ap->ap_data_transfer_length;
|
||||
ac->ac_data = dp;
|
||||
ac->ac_length = ap->ap_data_transfer_length;
|
||||
temp = (void *)(uintptr_t)ap->ap_data_transfer_address;
|
||||
|
||||
mtx_lock(&sc->amr_list_lock);
|
||||
error = amr_wait_command(ac);
|
||||
mtx_unlock(&sc->amr_list_lock);
|
||||
if (error)
|
||||
@ -706,8 +704,6 @@ amr_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag,
|
||||
mtx_unlock(&sc->amr_list_lock);
|
||||
if (dp != NULL)
|
||||
free(dp, M_AMR);
|
||||
if (ap != NULL)
|
||||
free(ap, M_AMR);
|
||||
return(error);
|
||||
}
|
||||
|
||||
@ -729,7 +725,7 @@ amr_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag, d_thread_t *
|
||||
unsigned long au_length;
|
||||
unsigned char *au_cmd;
|
||||
int *au_statusp, au_direction;
|
||||
int error, ac_flags = 0;
|
||||
int error;
|
||||
struct amr_passthrough *ap; /* 60 bytes */
|
||||
int logical_drives_changed = 0;
|
||||
|
||||
@ -832,8 +828,6 @@ amr_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag, d_thread_t *
|
||||
}
|
||||
|
||||
/* Allocate this now before the mutex gets held */
|
||||
if (au_cmd[0] == AMR_CMD_PASS)
|
||||
ap = malloc(sizeof(struct amr_passthrough), M_AMR, M_WAITOK|M_ZERO);
|
||||
|
||||
mtx_lock(&sc->amr_list_lock);
|
||||
while ((ac = amr_alloccmd(sc)) == NULL)
|
||||
@ -843,6 +837,9 @@ amr_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag, d_thread_t *
|
||||
if (au_cmd[0] == AMR_CMD_PASS) {
|
||||
int len;
|
||||
|
||||
ap = &ac->ac_ccb->ccb_pthru;
|
||||
bzero(ap, sizeof(struct amr_passthrough));
|
||||
|
||||
/* copy cdb */
|
||||
len = au_cmd[2];
|
||||
ap->ap_cdb_length = len;
|
||||
@ -860,13 +857,8 @@ amr_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag, d_thread_t *
|
||||
/* XXX what about the request-sense area? does the caller want it? */
|
||||
|
||||
/* build command */
|
||||
ac->ac_data = ap;
|
||||
ac->ac_length = sizeof(struct amr_passthrough);
|
||||
ac->ac_ccb_data = dp;
|
||||
ac->ac_ccb_length = au_length;
|
||||
|
||||
ac->ac_mailbox.mb_command = AMR_CMD_PASS;
|
||||
ac_flags = AMR_CMD_DATAIN|AMR_CMD_DATAOUT|AMR_CMD_CCB_DATAIN|AMR_CMD_CCB_DATAOUT;
|
||||
ac->ac_flags = AMR_CMD_CCB;
|
||||
|
||||
} else {
|
||||
/* direct command to controller */
|
||||
@ -878,14 +870,13 @@ amr_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag, d_thread_t *
|
||||
mbi->mb_param = au_cmd[2];
|
||||
mbi->mb_pad[0] = au_cmd[3];
|
||||
mbi->mb_drive = au_cmd[4];
|
||||
|
||||
/* build the command */
|
||||
ac->ac_data = dp;
|
||||
ac->ac_length = au_length;
|
||||
ac_flags = AMR_CMD_DATAIN|AMR_CMD_DATAOUT;
|
||||
ac->ac_flags = 0;
|
||||
}
|
||||
|
||||
ac->ac_flags = ac_flags;
|
||||
/* build the command */
|
||||
ac->ac_data = dp;
|
||||
ac->ac_length = au_length;
|
||||
ac->ac_flags |= AMR_CMD_DATAIN|AMR_CMD_DATAOUT;
|
||||
|
||||
/* run the command */
|
||||
error = amr_wait_command(ac);
|
||||
@ -899,7 +890,7 @@ amr_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag, d_thread_t *
|
||||
}
|
||||
debug(2, "copyout %ld bytes from %p -> %p", au_length, dp, au_buffer);
|
||||
if (dp != NULL)
|
||||
debug(2, "%jd", (uintptr_t)dp);
|
||||
debug(2, "%p status 0x%x", dp, ac->ac_status);
|
||||
*au_statusp = ac->ac_status;
|
||||
|
||||
out:
|
||||
@ -913,8 +904,6 @@ out:
|
||||
mtx_unlock(&sc->amr_list_lock);
|
||||
if (dp != NULL)
|
||||
free(dp, M_AMR);
|
||||
if (ap != NULL)
|
||||
free(ap, M_AMR);
|
||||
|
||||
#ifndef LSI
|
||||
if (logical_drives_changed)
|
||||
@ -1420,21 +1409,24 @@ amr_setup_polled_dmamap(void *arg, bus_dma_segment_t *segs, int nsegs, int err)
|
||||
{
|
||||
struct amr_command *ac = arg;
|
||||
struct amr_softc *sc = ac->ac_sc;
|
||||
int flags;
|
||||
int mb_channel;
|
||||
|
||||
flags = 0;
|
||||
if (ac->ac_flags & AMR_CMD_DATAIN)
|
||||
flags |= BUS_DMASYNC_PREREAD;
|
||||
if (ac->ac_flags & AMR_CMD_DATAOUT)
|
||||
flags |= BUS_DMASYNC_PREWRITE;
|
||||
amr_setup_sg(arg, segs, nsegs, err);
|
||||
|
||||
/* for AMR_CMD_CONFIG Read/Write the s/g count goes elsewhere */
|
||||
mb_channel = ((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_channel;
|
||||
if (ac->ac_mailbox.mb_command == AMR_CMD_CONFIG &&
|
||||
((mb_channel == AMR_CONFIG_READ_NVRAM_CONFIG) ||
|
||||
(mb_channel == AMR_CONFIG_WRITE_NVRAM_CONFIG)))
|
||||
((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_param = ac->ac_nsegments;
|
||||
|
||||
ac->ac_mailbox.mb_nsgelem = ac->ac_nsegments;
|
||||
ac->ac_mailbox.mb_physaddr = ac->ac_mb_physaddr;
|
||||
if (AC_IS_SG64(ac)) {
|
||||
amr_setup_dma64map(arg, segs, nsegs, err);
|
||||
bus_dmamap_sync(sc->amr_buffer64_dmat,ac->ac_dma64map, flags);
|
||||
} else {
|
||||
amr_setup_dmamap(arg, segs, nsegs, err);
|
||||
bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap, flags);
|
||||
ac->ac_sg64_hi = 0;
|
||||
ac->ac_sg64_lo = ac->ac_sgbusaddr;
|
||||
}
|
||||
|
||||
sc->amr_poll_command1(sc, ac);
|
||||
}
|
||||
|
||||
@ -1445,8 +1437,6 @@ amr_setup_polled_dmamap(void *arg, bus_dma_segment_t *segs, int nsegs, int err)
|
||||
static int
|
||||
amr_quartz_poll_command(struct amr_command *ac)
|
||||
{
|
||||
bus_dma_tag_t tag;
|
||||
bus_dmamap_t datamap;
|
||||
struct amr_softc *sc = ac->ac_sc;
|
||||
int error;
|
||||
|
||||
@ -1455,17 +1445,17 @@ amr_quartz_poll_command(struct amr_command *ac)
|
||||
error = 0;
|
||||
|
||||
if (AC_IS_SG64(ac)) {
|
||||
tag = sc->amr_buffer64_dmat;
|
||||
datamap = ac->ac_dma64map;
|
||||
ac->ac_tag = sc->amr_buffer64_dmat;
|
||||
ac->ac_datamap = ac->ac_dma64map;
|
||||
} else {
|
||||
tag = sc->amr_buffer_dmat;
|
||||
datamap = ac->ac_dmamap;
|
||||
ac->ac_tag = sc->amr_buffer_dmat;
|
||||
ac->ac_datamap = ac->ac_dmamap;
|
||||
}
|
||||
|
||||
/* now we have a slot, we can map the command (unmapped in amr_complete) */
|
||||
if (ac->ac_data != 0) {
|
||||
if (bus_dmamap_load(tag, datamap, ac->ac_data, ac->ac_length,
|
||||
amr_setup_polled_dmamap, ac, BUS_DMA_NOWAIT) != 0) {
|
||||
if (bus_dmamap_load(ac->ac_tag, ac->ac_datamap, ac->ac_data,
|
||||
ac->ac_length, amr_setup_polled_dmamap, ac, BUS_DMA_NOWAIT) != 0) {
|
||||
error = 1;
|
||||
}
|
||||
} else {
|
||||
@ -1494,10 +1484,7 @@ amr_quartz_poll_command1(struct amr_softc *sc, struct amr_command *ac)
|
||||
device_printf(sc->amr_dev, "adapter is busy\n");
|
||||
mtx_unlock(&sc->amr_hw_lock);
|
||||
if (ac->ac_data != NULL) {
|
||||
if (AC_IS_SG64(ac))
|
||||
bus_dmamap_unload(sc->amr_buffer64_dmat, ac->ac_dma64map);
|
||||
else
|
||||
bus_dmamap_unload(sc->amr_buffer_dmat, ac->ac_dmamap);
|
||||
bus_dmamap_unload(ac->ac_tag, ac->ac_datamap);
|
||||
}
|
||||
ac->ac_status=0;
|
||||
return(1);
|
||||
@ -1535,17 +1522,12 @@ amr_quartz_poll_command1(struct amr_softc *sc, struct amr_command *ac)
|
||||
|
||||
/* unmap the command's data buffer */
|
||||
if (ac->ac_flags & AMR_CMD_DATAIN) {
|
||||
bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap,
|
||||
BUS_DMASYNC_POSTREAD);
|
||||
bus_dmamap_sync(ac->ac_tag, ac->ac_datamap, BUS_DMASYNC_POSTREAD);
|
||||
}
|
||||
if (ac->ac_flags & AMR_CMD_DATAOUT) {
|
||||
bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap,
|
||||
BUS_DMASYNC_POSTWRITE);
|
||||
bus_dmamap_sync(ac->ac_tag, ac->ac_datamap, BUS_DMASYNC_POSTWRITE);
|
||||
}
|
||||
if (AC_IS_SG64(ac))
|
||||
bus_dmamap_unload(sc->amr_buffer64_dmat, ac->ac_dma64map);
|
||||
else
|
||||
bus_dmamap_unload(sc->amr_buffer_dmat, ac->ac_dmamap);
|
||||
bus_dmamap_unload(ac->ac_tag, ac->ac_datamap);
|
||||
|
||||
return(error);
|
||||
}
|
||||
@ -1574,223 +1556,108 @@ amr_freeslot(struct amr_command *ac)
|
||||
* These functions may be safely called multiple times on a given command.
|
||||
*/
|
||||
static void
|
||||
amr_setup_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error)
|
||||
amr_setup_sg(void *arg, bus_dma_segment_t *segs, int nsegments, int error)
|
||||
{
|
||||
struct amr_command *ac = (struct amr_command *)arg;
|
||||
struct amr_sgentry *sg;
|
||||
int i;
|
||||
u_int8_t *sgc;
|
||||
struct amr_sg64entry *sg64;
|
||||
int flags, i;
|
||||
|
||||
debug_called(3);
|
||||
|
||||
if (error)
|
||||
printf("amr_setup_sg: error %d\n", error);
|
||||
|
||||
/* get base address of s/g table */
|
||||
sg = ac->ac_sg.sg32;
|
||||
sg64 = ac->ac_sg.sg64;
|
||||
|
||||
/* save data physical address */
|
||||
|
||||
/* for AMR_CMD_CONFIG Read/Write the s/g count goes elsewhere */
|
||||
if (ac->ac_mailbox.mb_command == AMR_CMD_CONFIG && (
|
||||
((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_channel == AMR_CONFIG_READ_NVRAM_CONFIG ||
|
||||
((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_channel == AMR_CONFIG_WRITE_NVRAM_CONFIG)) {
|
||||
sgc = &(((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_param);
|
||||
if (AC_IS_SG64(ac)) {
|
||||
ac->ac_nsegments = nsegments;
|
||||
ac->ac_mb_physaddr = 0xffffffff;
|
||||
for (i = 0; i < nsegments; i++, sg64++) {
|
||||
sg64->sg_addr = segs[i].ds_addr;
|
||||
sg64->sg_count = segs[i].ds_len;
|
||||
}
|
||||
} else {
|
||||
sgc = &ac->ac_mailbox.mb_nsgelem;
|
||||
/* decide whether we need to populate the s/g table */
|
||||
if (nsegments < 2) {
|
||||
ac->ac_nsegments = 0;
|
||||
ac->ac_mb_physaddr = segs[0].ds_addr;
|
||||
} else {
|
||||
ac->ac_nsegments = nsegments;
|
||||
ac->ac_mb_physaddr = ac->ac_sgbusaddr;
|
||||
for (i = 0; i < nsegments; i++, sg++) {
|
||||
sg->sg_addr = segs[i].ds_addr;
|
||||
sg->sg_count = segs[i].ds_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* decide whether we need to populate the s/g table */
|
||||
if (nsegments < 2) {
|
||||
*sgc = 0;
|
||||
ac->ac_mailbox.mb_nsgelem = 0;
|
||||
ac->ac_mailbox.mb_physaddr = segs[0].ds_addr;
|
||||
} else {
|
||||
ac->ac_mailbox.mb_nsgelem = nsegments;
|
||||
*sgc = nsegments;
|
||||
/* XXX Setting these to 0 might not be needed. */
|
||||
ac->ac_sg64_lo = 0;
|
||||
flags = 0;
|
||||
if (ac->ac_flags & AMR_CMD_DATAIN)
|
||||
flags |= BUS_DMASYNC_PREREAD;
|
||||
if (ac->ac_flags & AMR_CMD_DATAOUT)
|
||||
flags |= BUS_DMASYNC_PREWRITE;
|
||||
bus_dmamap_sync(ac->ac_tag, ac->ac_datamap, flags);
|
||||
ac->ac_flags |= AMR_CMD_MAPPED;
|
||||
}
|
||||
|
||||
static void
|
||||
amr_setup_data(void *arg, bus_dma_segment_t *segs, int nsegs, int err)
|
||||
{
|
||||
struct amr_command *ac = arg;
|
||||
struct amr_softc *sc = ac->ac_sc;
|
||||
int mb_channel;
|
||||
|
||||
amr_setup_sg(arg, segs, nsegs, err);
|
||||
|
||||
/* for AMR_CMD_CONFIG Read/Write the s/g count goes elsewhere */
|
||||
mb_channel = ((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_channel;
|
||||
if (ac->ac_mailbox.mb_command == AMR_CMD_CONFIG &&
|
||||
((mb_channel == AMR_CONFIG_READ_NVRAM_CONFIG) ||
|
||||
(mb_channel == AMR_CONFIG_WRITE_NVRAM_CONFIG)))
|
||||
((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_param = ac->ac_nsegments;
|
||||
|
||||
ac->ac_mailbox.mb_nsgelem = ac->ac_nsegments;
|
||||
ac->ac_mailbox.mb_physaddr = ac->ac_mb_physaddr;
|
||||
if (AC_IS_SG64(ac)) {
|
||||
ac->ac_sg64_hi = 0;
|
||||
ac->ac_mailbox.mb_physaddr = ac->ac_sgbusaddr;
|
||||
for (i = 0; i < nsegments; i++, sg++) {
|
||||
sg->sg_addr = segs[i].ds_addr;
|
||||
sg->sg_count = segs[i].ds_len;
|
||||
}
|
||||
ac->ac_sg64_lo = ac->ac_sgbusaddr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
amr_setup_dma64map(void *arg, bus_dma_segment_t *segs, int nsegments, int error)
|
||||
{
|
||||
struct amr_command *ac = (struct amr_command *)arg;
|
||||
struct amr_sg64entry *sg;
|
||||
int i;
|
||||
u_int8_t *sgc;
|
||||
|
||||
debug_called(3);
|
||||
|
||||
/* get base address of s/g table */
|
||||
sg = ac->ac_sg.sg64;
|
||||
|
||||
/* save data physical address */
|
||||
|
||||
/* for AMR_CMD_CONFIG Read/Write the s/g count goes elsewhere */
|
||||
if (ac->ac_mailbox.mb_command == AMR_CMD_CONFIG && (
|
||||
((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_channel == AMR_CONFIG_READ_NVRAM_CONFIG ||
|
||||
((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_channel == AMR_CONFIG_WRITE_NVRAM_CONFIG)) {
|
||||
sgc = &(((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_param);
|
||||
} else {
|
||||
sgc = &ac->ac_mailbox.mb_nsgelem;
|
||||
}
|
||||
|
||||
ac->ac_mailbox.mb_nsgelem = nsegments;
|
||||
*sgc = nsegments;
|
||||
ac->ac_sg64_hi = 0;
|
||||
ac->ac_sg64_lo = ac->ac_sgbusaddr;
|
||||
ac->ac_mailbox.mb_physaddr = 0xffffffff;
|
||||
for (i = 0; i < nsegments; i++, sg++) {
|
||||
sg->sg_addr = segs[i].ds_addr;
|
||||
sg->sg_count = segs[i].ds_len;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
amr_setup_ccbmap(void *arg, bus_dma_segment_t *segs, int nsegments, int error)
|
||||
{
|
||||
struct amr_command *ac = (struct amr_command *)arg;
|
||||
struct amr_softc *sc = ac->ac_sc;
|
||||
struct amr_sgentry *sg;
|
||||
struct amr_passthrough *ap = (struct amr_passthrough *)ac->ac_data;
|
||||
struct amr_ext_passthrough *aep = (struct amr_ext_passthrough *)ac->ac_data;
|
||||
int i;
|
||||
|
||||
/* get base address of s/g table */
|
||||
sg = ac->ac_sg.sg32;
|
||||
|
||||
/* decide whether we need to populate the s/g table */
|
||||
if( ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS ) {
|
||||
if (nsegments < 2) {
|
||||
aep->ap_no_sg_elements = 0;
|
||||
aep->ap_data_transfer_address = segs[0].ds_addr;
|
||||
} else {
|
||||
/* save s/g table information in passthrough */
|
||||
aep->ap_no_sg_elements = nsegments;
|
||||
aep->ap_data_transfer_address = ac->ac_sgbusaddr;
|
||||
/*
|
||||
* populate s/g table (overwrites previous call which mapped the
|
||||
* passthrough)
|
||||
*/
|
||||
for (i = 0; i < nsegments; i++, sg++) {
|
||||
sg->sg_addr = segs[i].ds_addr;
|
||||
sg->sg_count = segs[i].ds_len;
|
||||
debug(3, " %d: 0x%x/%d", i, sg->sg_addr, sg->sg_count);
|
||||
}
|
||||
}
|
||||
debug(3, "slot %d %d segments at 0x%x\n", ac->ac_slot,
|
||||
aep->ap_no_sg_elements, aep->ap_data_transfer_address);
|
||||
} else {
|
||||
if (nsegments < 2) {
|
||||
ap->ap_no_sg_elements = 0;
|
||||
ap->ap_data_transfer_address = segs[0].ds_addr;
|
||||
} else {
|
||||
/* save s/g table information in passthrough */
|
||||
ap->ap_no_sg_elements = nsegments;
|
||||
ap->ap_data_transfer_address = ac->ac_sgbusaddr;
|
||||
/*
|
||||
* populate s/g table (overwrites previous call which mapped the
|
||||
* passthrough)
|
||||
*/
|
||||
for (i = 0; i < nsegments; i++, sg++) {
|
||||
sg->sg_addr = segs[i].ds_addr;
|
||||
sg->sg_count = segs[i].ds_len;
|
||||
debug(3, " %d: 0x%x/%d", i, sg->sg_addr, sg->sg_count);
|
||||
}
|
||||
}
|
||||
debug(3, "slot %d %d segments at 0x%x\n", ac->ac_slot,
|
||||
ap->ap_no_sg_elements, ap->ap_data_transfer_address);
|
||||
}
|
||||
if (ac->ac_flags & AMR_CMD_CCB_DATAIN)
|
||||
bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap,
|
||||
BUS_DMASYNC_PREREAD);
|
||||
if (ac->ac_flags & AMR_CMD_CCB_DATAOUT)
|
||||
bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap,
|
||||
BUS_DMASYNC_PREWRITE);
|
||||
if ((ac->ac_flags & (AMR_CMD_CCB_DATAIN | AMR_CMD_CCB_DATAOUT)) == 0)
|
||||
panic("no direction for ccb?\n");
|
||||
|
||||
if (ac->ac_flags & AMR_CMD_DATAIN)
|
||||
bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap,BUS_DMASYNC_PREREAD);
|
||||
if (ac->ac_flags & AMR_CMD_DATAOUT)
|
||||
bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap,BUS_DMASYNC_PREWRITE);
|
||||
|
||||
ac->ac_flags |= AMR_CMD_MAPPED;
|
||||
|
||||
if (sc->amr_submit_command(ac) == EBUSY) {
|
||||
amr_freeslot(ac);
|
||||
amr_requeue_ready(ac);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
amr_setup_ccb64map(void *arg, bus_dma_segment_t *segs, int nsegments, int error)
|
||||
amr_setup_ccb(void *arg, bus_dma_segment_t *segs, int nsegs, int err)
|
||||
{
|
||||
struct amr_command *ac = (struct amr_command *)arg;
|
||||
struct amr_softc *sc = ac->ac_sc;
|
||||
struct amr_sg64entry *sg;
|
||||
struct amr_passthrough *ap = (struct amr_passthrough *)ac->ac_data;
|
||||
struct amr_ext_passthrough *aep = (struct amr_ext_passthrough *)ac->ac_data;
|
||||
int i;
|
||||
struct amr_command *ac = arg;
|
||||
struct amr_softc *sc = ac->ac_sc;
|
||||
struct amr_passthrough *ap = &ac->ac_ccb->ccb_pthru;
|
||||
struct amr_ext_passthrough *aep = &ac->ac_ccb->ccb_epthru;
|
||||
|
||||
/* get base address of s/g table */
|
||||
sg = ac->ac_sg.sg64;
|
||||
/* Set up the mailbox portion of the command to point at the ccb */
|
||||
ac->ac_mailbox.mb_nsgelem = 0;
|
||||
ac->ac_mailbox.mb_physaddr = ac->ac_ccb_busaddr;
|
||||
|
||||
/* decide whether we need to populate the s/g table */
|
||||
if( ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS ) {
|
||||
/* save s/g table information in passthrough */
|
||||
aep->ap_no_sg_elements = nsegments;
|
||||
aep->ap_data_transfer_address = ac->ac_sgbusaddr;
|
||||
/*
|
||||
* populate s/g table (overwrites previous call which mapped the
|
||||
* passthrough)
|
||||
*/
|
||||
for (i = 0; i < nsegments; i++, sg++) {
|
||||
sg->sg_addr = segs[i].ds_addr;
|
||||
sg->sg_count = segs[i].ds_len;
|
||||
debug(3, " %d: 0x%lx/%d", i, (u_long)sg->sg_addr, sg->sg_count);
|
||||
}
|
||||
debug(3, "slot %d %d segments at 0x%x\n", ac->ac_slot,
|
||||
aep->ap_no_sg_elements, aep->ap_data_transfer_address);
|
||||
} else {
|
||||
/* save s/g table information in passthrough */
|
||||
ap->ap_no_sg_elements = nsegments;
|
||||
ap->ap_data_transfer_address = ac->ac_sgbusaddr;
|
||||
/*
|
||||
* populate s/g table (overwrites previous call which mapped the
|
||||
* passthrough)
|
||||
*/
|
||||
for (i = 0; i < nsegments; i++, sg++) {
|
||||
sg->sg_addr = segs[i].ds_addr;
|
||||
sg->sg_count = segs[i].ds_len;
|
||||
debug(3, " %d: 0x%lx/%d", i, (u_long)sg->sg_addr, sg->sg_count);
|
||||
}
|
||||
debug(3, "slot %d %d segments at 0x%x\n", ac->ac_slot,
|
||||
ap->ap_no_sg_elements, ap->ap_data_transfer_address);
|
||||
amr_setup_sg(arg, segs, nsegs, err);
|
||||
|
||||
switch (ac->ac_mailbox.mb_command) {
|
||||
case AMR_CMD_EXTPASS:
|
||||
aep->ap_no_sg_elements = ac->ac_nsegments;
|
||||
aep->ap_data_transfer_address = ac->ac_mb_physaddr;
|
||||
break;
|
||||
case AMR_CMD_PASS:
|
||||
ap->ap_no_sg_elements = ac->ac_nsegments;
|
||||
ap->ap_data_transfer_address = ac->ac_mb_physaddr;
|
||||
break;
|
||||
default:
|
||||
panic("Unknown ccb command");
|
||||
}
|
||||
if (ac->ac_flags & AMR_CMD_CCB_DATAIN)
|
||||
bus_dmamap_sync(sc->amr_buffer64_dmat, ac->ac_ccb_dma64map,
|
||||
BUS_DMASYNC_PREREAD);
|
||||
if (ac->ac_flags & AMR_CMD_CCB_DATAOUT)
|
||||
bus_dmamap_sync(sc->amr_buffer64_dmat, ac->ac_ccb_dma64map,
|
||||
BUS_DMASYNC_PREWRITE);
|
||||
if ((ac->ac_flags & (AMR_CMD_CCB_DATAIN | AMR_CMD_CCB_DATAOUT)) == 0)
|
||||
panic("no direction for ccb?\n");
|
||||
|
||||
if (ac->ac_flags & AMR_CMD_DATAIN)
|
||||
bus_dmamap_sync(sc->amr_buffer64_dmat, ac->ac_dma64map,
|
||||
BUS_DMASYNC_PREREAD);
|
||||
if (ac->ac_flags & AMR_CMD_DATAOUT)
|
||||
bus_dmamap_sync(sc->amr_buffer64_dmat, ac->ac_dma64map,
|
||||
BUS_DMASYNC_PREWRITE);
|
||||
|
||||
ac->ac_flags |= AMR_CMD_MAPPED;
|
||||
|
||||
if (sc->amr_submit_command(ac) == EBUSY) {
|
||||
amr_freeslot(ac);
|
||||
@ -1798,65 +1665,32 @@ amr_setup_ccb64map(void *arg, bus_dma_segment_t *segs, int nsegments, int error)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
amr_setup_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nsegments,
|
||||
int error)
|
||||
{
|
||||
struct amr_command *ac = (struct amr_command *)arg;
|
||||
struct amr_softc *sc = ac->ac_sc;
|
||||
|
||||
amr_setup_dmamap(arg, segs, nsegments, error);
|
||||
|
||||
if (bus_dmamap_load(sc->amr_buffer_dmat, ac->ac_ccb_dmamap,
|
||||
ac->ac_ccb_data, ac->ac_ccb_length, amr_setup_ccbmap, ac,
|
||||
0) == EINPROGRESS) {
|
||||
sc->amr_state |= AMR_STATE_QUEUE_FRZN;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
amr_setup_dma64map_cb(void *arg, bus_dma_segment_t *segs, int nsegments,
|
||||
int error)
|
||||
{
|
||||
struct amr_command *ac = (struct amr_command *)arg;
|
||||
struct amr_softc *sc = ac->ac_sc;
|
||||
|
||||
amr_setup_dma64map(arg, segs, nsegments, error);
|
||||
|
||||
if (bus_dmamap_load(sc->amr_buffer64_dmat, ac->ac_ccb_dma64map,
|
||||
ac->ac_ccb_data, ac->ac_ccb_length, amr_setup_ccb64map, ac,
|
||||
0) == EINPROGRESS) {
|
||||
sc->amr_state |= AMR_STATE_QUEUE_FRZN;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
amr_mapcmd(struct amr_command *ac)
|
||||
{
|
||||
bus_dma_tag_t tag;
|
||||
bus_dmamap_t datamap;
|
||||
bus_dmamap_callback_t *cb;
|
||||
struct amr_softc *sc = ac->ac_sc;
|
||||
|
||||
debug_called(3);
|
||||
|
||||
if (AC_IS_SG64(ac)) {
|
||||
tag = sc->amr_buffer64_dmat;
|
||||
datamap = ac->ac_dma64map;
|
||||
cb = amr_setup_dma64map_cb;
|
||||
ac->ac_tag = sc->amr_buffer64_dmat;
|
||||
ac->ac_datamap = ac->ac_dma64map;
|
||||
} else {
|
||||
tag = sc->amr_buffer_dmat;
|
||||
datamap = ac->ac_dmamap;
|
||||
cb = amr_setup_dmamap_cb;
|
||||
ac->ac_tag = sc->amr_buffer_dmat;
|
||||
ac->ac_datamap = ac->ac_dmamap;
|
||||
}
|
||||
|
||||
if (ac->ac_flags & AMR_CMD_CCB)
|
||||
cb = amr_setup_ccb;
|
||||
else
|
||||
cb = amr_setup_data;
|
||||
|
||||
/* if the command involves data at all, and hasn't been mapped */
|
||||
if ((ac->ac_flags & AMR_CMD_MAPPED) == 0 && (ac->ac_data != NULL)) {
|
||||
if (ac->ac_ccb_data == NULL)
|
||||
cb = amr_setup_data_dmamap;
|
||||
/* map the data buffers into bus space and build the s/g list */
|
||||
if (bus_dmamap_load(tag, datamap, ac->ac_data, ac->ac_length,
|
||||
cb, ac, 0) == EINPROGRESS) {
|
||||
if (bus_dmamap_load(ac->ac_tag, ac->ac_datamap, ac->ac_data,
|
||||
ac->ac_length, cb, ac, 0) == EINPROGRESS) {
|
||||
sc->amr_state |= AMR_STATE_QUEUE_FRZN;
|
||||
}
|
||||
} else {
|
||||
@ -1872,7 +1706,6 @@ amr_mapcmd(struct amr_command *ac)
|
||||
static void
|
||||
amr_unmapcmd(struct amr_command *ac)
|
||||
{
|
||||
struct amr_softc *sc = ac->ac_sc;
|
||||
int flag;
|
||||
|
||||
debug_called(3);
|
||||
@ -1888,63 +1721,14 @@ amr_unmapcmd(struct amr_command *ac)
|
||||
if (ac->ac_flags & AMR_CMD_DATAOUT)
|
||||
flag |= BUS_DMASYNC_POSTWRITE;
|
||||
|
||||
if (AC_IS_SG64(ac)) {
|
||||
bus_dmamap_sync(sc->amr_buffer64_dmat, ac->ac_dma64map, flag);
|
||||
bus_dmamap_unload(sc->amr_buffer64_dmat, ac->ac_dma64map);
|
||||
} else {
|
||||
bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_dmamap, flag);
|
||||
bus_dmamap_unload(sc->amr_buffer_dmat, ac->ac_dmamap);
|
||||
}
|
||||
bus_dmamap_sync(ac->ac_tag, ac->ac_datamap, flag);
|
||||
bus_dmamap_unload(ac->ac_tag, ac->ac_datamap);
|
||||
}
|
||||
|
||||
if (ac->ac_ccb_data != NULL) {
|
||||
|
||||
flag = 0;
|
||||
if (ac->ac_flags & AMR_CMD_CCB_DATAIN)
|
||||
flag |= BUS_DMASYNC_POSTREAD;
|
||||
if (ac->ac_flags & AMR_CMD_CCB_DATAOUT)
|
||||
flag |= BUS_DMASYNC_POSTWRITE;
|
||||
|
||||
if (AC_IS_SG64(ac)) {
|
||||
bus_dmamap_sync(sc->amr_buffer64_dmat,ac->ac_ccb_dma64map,flag);
|
||||
bus_dmamap_unload(sc->amr_buffer64_dmat, ac->ac_ccb_dma64map);
|
||||
} else {
|
||||
bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap, flag);
|
||||
bus_dmamap_unload(sc->amr_buffer_dmat, ac->ac_ccb_dmamap);
|
||||
}
|
||||
}
|
||||
ac->ac_flags &= ~AMR_CMD_MAPPED;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
amr_setup_data_dmamap(void *arg, bus_dma_segment_t *segs, int nsegs, int err)
|
||||
{
|
||||
struct amr_command *ac = arg;
|
||||
struct amr_softc *sc = ac->ac_sc;
|
||||
int flags;
|
||||
|
||||
flags = 0;
|
||||
if (ac->ac_flags & AMR_CMD_DATAIN)
|
||||
flags |= BUS_DMASYNC_PREREAD;
|
||||
if (ac->ac_flags & AMR_CMD_DATAOUT)
|
||||
flags |= BUS_DMASYNC_PREWRITE;
|
||||
|
||||
if (AC_IS_SG64(ac)) {
|
||||
amr_setup_dma64map(arg, segs, nsegs, err);
|
||||
bus_dmamap_sync(sc->amr_buffer64_dmat,ac->ac_dma64map, flags);
|
||||
} else {
|
||||
amr_setup_dmamap(arg, segs, nsegs, err);
|
||||
bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap, flags);
|
||||
}
|
||||
ac->ac_flags |= AMR_CMD_MAPPED;
|
||||
|
||||
if (sc->amr_submit_command(ac) == EBUSY) {
|
||||
amr_freeslot(ac);
|
||||
amr_requeue_ready(ac);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
* Take a command and give it to the controller, returns 0 if successful, or
|
||||
* EBUSY if the command should be retried later.
|
||||
@ -2124,8 +1908,9 @@ amr_alloccmd(struct amr_softc *sc)
|
||||
ac->ac_flags = 0;
|
||||
ac->ac_bio = NULL;
|
||||
ac->ac_data = NULL;
|
||||
ac->ac_ccb_data = NULL;
|
||||
ac->ac_complete = NULL;
|
||||
ac->ac_tag = NULL;
|
||||
ac->ac_datamap = NULL;
|
||||
return(ac);
|
||||
}
|
||||
|
||||
@ -2177,12 +1962,15 @@ amr_alloccmd_cluster(struct amr_softc *sc)
|
||||
ac->ac_sg.sg32 = sc->amr_sgtable + (ac->ac_slot * AMR_NSEG);
|
||||
}
|
||||
|
||||
if (bus_dmamap_create(sc->amr_buffer_dmat, 0, &ac->ac_dmamap) ||
|
||||
bus_dmamap_create(sc->amr_buffer_dmat, 0, &ac->ac_ccb_dmamap) ||
|
||||
(AMR_IS_SG64(sc) &&
|
||||
(bus_dmamap_create(sc->amr_buffer64_dmat, 0,&ac->ac_dma64map) ||
|
||||
bus_dmamap_create(sc->amr_buffer64_dmat, 0, &ac->ac_ccb_dma64map))))
|
||||
break;
|
||||
ac->ac_ccb = sc->amr_ccb + ac->ac_slot;
|
||||
ac->ac_ccb_busaddr = sc->amr_ccb_busaddr +
|
||||
(ac->ac_slot * sizeof(union amr_ccb));
|
||||
|
||||
if (bus_dmamap_create(sc->amr_buffer_dmat, 0, &ac->ac_dmamap))
|
||||
break;
|
||||
if (AMR_IS_SG64(sc) &&
|
||||
(bus_dmamap_create(sc->amr_buffer64_dmat, 0,&ac->ac_dma64map)))
|
||||
break;
|
||||
amr_releasecmd(ac);
|
||||
if (++nextslot > sc->amr_maxio)
|
||||
break;
|
||||
@ -2202,10 +1990,8 @@ amr_freecmd_cluster(struct amr_command_cluster *acc)
|
||||
|
||||
for (i = 0; i < AMR_CMD_CLUSTERCOUNT; i++) {
|
||||
bus_dmamap_destroy(sc->amr_buffer_dmat, acc->acc_command[i].ac_dmamap);
|
||||
bus_dmamap_destroy(sc->amr_buffer_dmat, acc->acc_command[i].ac_ccb_dmamap);
|
||||
if (AMR_IS_SG64(sc))
|
||||
bus_dmamap_destroy(sc->amr_buffer64_dmat, acc->acc_command[i].ac_dma64map);
|
||||
bus_dmamap_destroy(sc->amr_buffer64_dmat, acc->acc_command[i].ac_ccb_dma64map);
|
||||
}
|
||||
free(acc, M_AMR);
|
||||
}
|
||||
|
@ -222,16 +222,16 @@ amr_cam_action(struct cam_sim *sim, union ccb *ccb)
|
||||
|
||||
/* check the CDB length */
|
||||
if (csio->cdb_len > AMR_MAX_EXTCDB_LEN)
|
||||
ccbh->status = CAM_REQ_CMP_ERR;
|
||||
ccbh->status = CAM_REQ_INVALID;
|
||||
|
||||
if ((csio->cdb_len > AMR_MAX_CDB_LEN) &&
|
||||
(sc->support_ext_cdb == 0))
|
||||
ccbh->status = CAM_REQ_CMP_ERR;
|
||||
ccbh->status = CAM_REQ_INVALID;
|
||||
|
||||
/* check that the CDB pointer is not to a physical address */
|
||||
if ((ccbh->flags & CAM_CDB_POINTER) &&
|
||||
(ccbh->flags & CAM_CDB_PHYS))
|
||||
ccbh->status = CAM_REQ_CMP_ERR;
|
||||
ccbh->status = CAM_REQ_INVALID;
|
||||
/*
|
||||
* if there is data transfer, it must be to/from a virtual
|
||||
* address
|
||||
@ -239,10 +239,10 @@ amr_cam_action(struct cam_sim *sim, union ccb *ccb)
|
||||
if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
|
||||
if (ccbh->flags & CAM_DATA_PHYS)
|
||||
/* we can't map it */
|
||||
ccbh->status = CAM_REQ_CMP_ERR;
|
||||
ccbh->status = CAM_REQ_INVALID;
|
||||
if (ccbh->flags & CAM_SCATTER_VALID)
|
||||
/* we want to do the s/g setup */
|
||||
ccbh->status = CAM_REQ_CMP_ERR;
|
||||
ccbh->status = CAM_REQ_INVALID;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -252,7 +252,7 @@ amr_cam_action(struct cam_sim *sim, union ccb *ccb)
|
||||
* devices appear echoed.
|
||||
*/
|
||||
if (csio->ccb_h.target_lun != 0)
|
||||
ccbh->status = CAM_REQ_CMP_ERR;
|
||||
ccbh->status = CAM_DEV_NOT_THERE;
|
||||
|
||||
/* if we're happy with the request, queue it for attention */
|
||||
if (ccbh->status == CAM_REQ_INPROG) {
|
||||
@ -405,13 +405,15 @@ amr_cam_command(struct amr_softc *sc, struct amr_command **acp)
|
||||
* Build a passthrough command.
|
||||
*/
|
||||
|
||||
/* construct command */
|
||||
if ((ac = amr_alloccmd(sc)) == NULL) {
|
||||
error = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* construct passthrough */
|
||||
if (sc->support_ext_cdb ) {
|
||||
if ((aep = malloc(sizeof(*aep), M_AMRCAM, M_NOWAIT | M_ZERO))
|
||||
== NULL) {
|
||||
error = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
aep = &ac->ac_ccb->ccb_epthru;
|
||||
aep->ap_timeout = 2;
|
||||
aep->ap_ars = 1;
|
||||
aep->ap_request_sense_length = 14;
|
||||
@ -437,11 +439,7 @@ amr_cam_command(struct amr_softc *sc, struct amr_command **acp)
|
||||
aep->ap_scsi_id, aep->ap_logical_drive_no);
|
||||
|
||||
} else {
|
||||
if ((ap = malloc(sizeof(*ap), M_AMRCAM, M_NOWAIT | M_ZERO))
|
||||
== NULL) {
|
||||
error = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
ap = &ac->ac_ccb->ccb_pthru;
|
||||
ap->ap_timeout = 0;
|
||||
ap->ap_ars = 1;
|
||||
ap->ap_request_sense_length = 14;
|
||||
@ -467,30 +465,20 @@ amr_cam_command(struct amr_softc *sc, struct amr_command **acp)
|
||||
ap->ap_scsi_id, ap->ap_logical_drive_no);
|
||||
}
|
||||
|
||||
/* construct command */
|
||||
if ((ac = amr_alloccmd(sc)) == NULL) {
|
||||
error = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
ac->ac_flags |= AMR_CMD_CCB;
|
||||
|
||||
ac->ac_flags |= AMR_CMD_DATAOUT | AMR_CMD_DATAIN;
|
||||
|
||||
ac->ac_ccb_data = csio->data_ptr;
|
||||
ac->ac_ccb_length = csio->dxfer_len;
|
||||
ac->ac_data = csio->data_ptr;
|
||||
ac->ac_length = csio->dxfer_len;
|
||||
if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
|
||||
ac->ac_flags |= AMR_CMD_CCB_DATAIN;
|
||||
ac->ac_flags |= AMR_CMD_DATAIN;
|
||||
if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)
|
||||
ac->ac_flags |= AMR_CMD_CCB_DATAOUT;
|
||||
ac->ac_flags |= AMR_CMD_DATAOUT;
|
||||
|
||||
ac->ac_private = csio;
|
||||
ac->ac_complete = amr_cam_complete;
|
||||
if ( sc->support_ext_cdb ) {
|
||||
ac->ac_data = aep;
|
||||
ac->ac_length = sizeof(*aep);
|
||||
ac->ac_mailbox.mb_command = AMR_CMD_EXTPASS;
|
||||
} else {
|
||||
ac->ac_data = ap;
|
||||
ac->ac_length = sizeof(*ap);
|
||||
ac->ac_mailbox.mb_command = AMR_CMD_PASS;
|
||||
}
|
||||
|
||||
@ -498,10 +486,6 @@ out:
|
||||
if (error != 0) {
|
||||
if (ac != NULL)
|
||||
amr_releasecmd(ac);
|
||||
if (ap != NULL)
|
||||
free(ap, M_AMRCAM);
|
||||
if (aep != NULL)
|
||||
free(aep, M_AMRCAM);
|
||||
if (csio != NULL)
|
||||
/* put it back and try again later */
|
||||
amr_requeue_ccb(sc, (union ccb *)csio);
|
||||
@ -532,19 +516,20 @@ amr_cam_complete(struct amr_command *ac)
|
||||
struct scsi_inquiry_data *inq;
|
||||
int scsi_status, cdb0;
|
||||
|
||||
ap = (struct amr_passthrough *)ac->ac_data;
|
||||
aep = (struct amr_ext_passthrough *)ac->ac_data;
|
||||
ap = &ac->ac_ccb->ccb_pthru;
|
||||
aep = &ac->ac_ccb->ccb_epthru;
|
||||
csio = (struct ccb_scsiio *)ac->ac_private;
|
||||
inq = (struct scsi_inquiry_data *)csio->data_ptr;
|
||||
|
||||
if (ac->ac_length == sizeof(*ap))
|
||||
scsi_status = ap->ap_scsi_status;
|
||||
else
|
||||
if (ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS)
|
||||
scsi_status = aep->ap_scsi_status;
|
||||
else
|
||||
scsi_status = ap->ap_scsi_status;
|
||||
debug(1, "status 0x%x AP scsi_status 0x%x", ac->ac_status,
|
||||
scsi_status);
|
||||
|
||||
if (ac->ac_status != AMR_STATUS_SUCCESS) {
|
||||
/* Make sure the status is sane */
|
||||
if ((ac->ac_status != AMR_STATUS_SUCCESS) && (scsi_status == 0)) {
|
||||
csio->ccb_h.status = CAM_REQ_CMP_ERR;
|
||||
goto out;
|
||||
}
|
||||
@ -561,10 +546,10 @@ amr_cam_complete(struct amr_command *ac)
|
||||
/* handle passthrough SCSI status */
|
||||
switch(scsi_status) {
|
||||
case 0: /* completed OK */
|
||||
if (ac->ac_length == sizeof(*ap))
|
||||
cdb0 = ap->ap_cdb[0];
|
||||
else
|
||||
if (ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS)
|
||||
cdb0 = aep->ap_cdb[0];
|
||||
else
|
||||
cdb0 = ap->ap_cdb[0];
|
||||
if ((cdb0 == INQUIRY) && (SID_TYPE(inq) == T_DIRECT))
|
||||
inq->device = (inq->device & 0xe0) | T_NODEVICE;
|
||||
csio->ccb_h.status = CAM_REQ_CMP;
|
||||
@ -573,11 +558,11 @@ amr_cam_complete(struct amr_command *ac)
|
||||
case 0x02:
|
||||
csio->ccb_h.status = CAM_SCSI_STATUS_ERROR;
|
||||
csio->scsi_status = SCSI_STATUS_CHECK_COND;
|
||||
if (ac->ac_length == sizeof(*ap))
|
||||
bcopy(ap->ap_request_sense_area, &csio->sense_data,
|
||||
if (ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS)
|
||||
bcopy(aep->ap_request_sense_area, &csio->sense_data,
|
||||
AMR_MAX_REQ_SENSE_LEN);
|
||||
else
|
||||
bcopy(aep->ap_request_sense_area, &csio->sense_data,
|
||||
bcopy(ap->ap_request_sense_area, &csio->sense_data,
|
||||
AMR_MAX_REQ_SENSE_LEN);
|
||||
csio->sense_len = AMR_MAX_REQ_SENSE_LEN;
|
||||
csio->ccb_h.status |= CAM_AUTOSNS_VALID;
|
||||
@ -590,20 +575,20 @@ amr_cam_complete(struct amr_command *ac)
|
||||
case 0xf0:
|
||||
case 0xf4:
|
||||
default:
|
||||
csio->ccb_h.status = CAM_REQ_CMP_ERR;
|
||||
/*
|
||||
* Non-zero LUNs are already filtered, so there's no need
|
||||
* to return CAM_DEV_NOT_THERE.
|
||||
*/
|
||||
csio->ccb_h.status = CAM_SEL_TIMEOUT;
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
if (ac->ac_length == sizeof(*ap))
|
||||
free(ap, M_AMRCAM);
|
||||
else
|
||||
free(aep, M_AMRCAM);
|
||||
if ((csio->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)
|
||||
debug(2, "%*D\n", imin(csio->dxfer_len, 16), csio->data_ptr,
|
||||
" ");
|
||||
|
||||
mtx_unlock(&ac->ac_sc->amr_list_lock);
|
||||
mtx_lock(&ac->ac_sc->amr_list_lock);
|
||||
xpt_done((union ccb *)csio);
|
||||
amr_releasecmd(ac);
|
||||
mtx_unlock(&ac->ac_sc->amr_list_lock);
|
||||
|
@ -86,10 +86,10 @@ static int amr_pci_suspend(device_t dev);
|
||||
static int amr_pci_resume(device_t dev);
|
||||
static void amr_pci_intr(void *arg);
|
||||
static void amr_pci_free(struct amr_softc *sc);
|
||||
static void amr_sglist_map_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error);
|
||||
static void amr_sglist_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error);
|
||||
static int amr_sglist_map(struct amr_softc *sc);
|
||||
static void amr_setup_mbox_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error);
|
||||
static int amr_setup_mbox(struct amr_softc *sc);
|
||||
static int amr_ccb_map(struct amr_softc *sc);
|
||||
|
||||
static u_int amr_force_sg32 = 0;
|
||||
TUNABLE_INT("hw.amr.force_sg32", &amr_force_sg32);
|
||||
@ -303,7 +303,7 @@ amr_pci_attach(device_t dev)
|
||||
NULL, NULL, /* filter, filterarg */
|
||||
MAXBSIZE, AMR_NSEG, /* maxsize, nsegments */
|
||||
MAXBSIZE, /* maxsegsize */
|
||||
BUS_DMA_ALLOCNOW, /* flags */
|
||||
0, /* flags */
|
||||
busdma_lock_mutex, /* lockfunc */
|
||||
&sc->amr_list_lock, /* lockarg */
|
||||
&sc->amr_buffer_dmat)) {
|
||||
@ -318,7 +318,7 @@ amr_pci_attach(device_t dev)
|
||||
NULL, NULL, /* filter, filterarg */
|
||||
MAXBSIZE, AMR_NSEG, /* maxsize, nsegments */
|
||||
MAXBSIZE, /* maxsegsize */
|
||||
BUS_DMA_ALLOCNOW, /* flags */
|
||||
0, /* flags */
|
||||
busdma_lock_mutex, /* lockfunc */
|
||||
&sc->amr_list_lock, /* lockarg */
|
||||
&sc->amr_buffer64_dmat)) {
|
||||
@ -343,9 +343,13 @@ amr_pci_attach(device_t dev)
|
||||
*/
|
||||
if (amr_sglist_map(sc))
|
||||
goto out;
|
||||
|
||||
debug(2, "s/g list mapped");
|
||||
|
||||
if (amr_ccb_map(sc))
|
||||
goto out;
|
||||
debug(2, "ccb mapped");
|
||||
|
||||
|
||||
/*
|
||||
* Do bus-independant initialisation, bring controller online.
|
||||
*/
|
||||
@ -469,7 +473,7 @@ amr_pci_intr(void *arg)
|
||||
{
|
||||
struct amr_softc *sc = (struct amr_softc *)arg;
|
||||
|
||||
debug_called(2);
|
||||
debug_called(3);
|
||||
|
||||
/* collect finished commands, queue anything waiting */
|
||||
amr_done(sc);
|
||||
@ -495,6 +499,12 @@ amr_pci_free(struct amr_softc *sc)
|
||||
if (sc->amr_buffer64_dmat)
|
||||
bus_dma_tag_destroy(sc->amr_buffer64_dmat);
|
||||
|
||||
/* free and destroy DMA memory and tag for passthrough pool */
|
||||
if (sc->amr_ccb)
|
||||
bus_dmamem_free(sc->amr_ccb_dmat, sc->amr_ccb, sc->amr_ccb_dmamap);
|
||||
if (sc->amr_ccb_dmat)
|
||||
bus_dma_tag_destroy(sc->amr_ccb_dmat);
|
||||
|
||||
/* free and destroy DMA memory and tag for s/g lists */
|
||||
if (sc->amr_sgtable)
|
||||
bus_dmamem_free(sc->amr_sg_dmat, sc->amr_sgtable, sc->amr_sg_dmamap);
|
||||
@ -530,14 +540,14 @@ amr_pci_free(struct amr_softc *sc)
|
||||
* Allocate and map the scatter/gather table in bus space.
|
||||
*/
|
||||
static void
|
||||
amr_sglist_map_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
|
||||
amr_sglist_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
|
||||
{
|
||||
struct amr_softc *sc = (struct amr_softc *)arg;
|
||||
uint32_t *addr;
|
||||
|
||||
debug_called(1);
|
||||
|
||||
/* save base of s/g table's address in bus space */
|
||||
sc->amr_sgbusaddr = segs->ds_addr;
|
||||
addr = arg;
|
||||
*addr = segs[0].ds_addr;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -562,7 +572,7 @@ amr_sglist_map(struct amr_softc *sc)
|
||||
segsize = sizeof(struct amr_sgentry) * AMR_NSEG * AMR_MAXCMD;
|
||||
|
||||
error = bus_dma_tag_create(sc->amr_parent_dmat, /* parent */
|
||||
1, 0, /* alignment,boundary */
|
||||
512, 0, /* alignment,boundary */
|
||||
BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
|
||||
BUS_SPACE_MAXADDR, /* highaddr */
|
||||
NULL, NULL, /* filter, filterarg */
|
||||
@ -597,7 +607,7 @@ retry:
|
||||
device_printf(sc->amr_dev, "can't allocate s/g table\n");
|
||||
return(ENOMEM);
|
||||
}
|
||||
bus_dmamap_load(sc->amr_sg_dmat, sc->amr_sg_dmamap, p, segsize, amr_sglist_map_helper, sc, 0);
|
||||
bus_dmamap_load(sc->amr_sg_dmat, sc->amr_sg_dmamap, p, segsize, amr_sglist_helper, &sc->amr_sgbusaddr, 0);
|
||||
if (sc->amr_sgbusaddr < 0x2000) {
|
||||
debug(1, "s/g table too low (0x%x), reallocating\n", sc->amr_sgbusaddr);
|
||||
goto retry;
|
||||
@ -613,25 +623,14 @@ retry:
|
||||
/********************************************************************************
|
||||
* Allocate and set up mailbox areas for the controller (sc)
|
||||
*
|
||||
* The basic mailbox structure should be 16-byte aligned. This means that the
|
||||
* mailbox64 structure has 4 bytes hanging off the bottom.
|
||||
* The basic mailbox structure should be 16-byte aligned.
|
||||
*/
|
||||
static void
|
||||
amr_setup_mbox_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error)
|
||||
{
|
||||
struct amr_softc *sc = (struct amr_softc *)arg;
|
||||
|
||||
debug_called(1);
|
||||
|
||||
/* save phsyical base of the basic mailbox structure */
|
||||
sc->amr_mailboxphys = segs->ds_addr + offsetof(struct amr_mailbox64, mb);
|
||||
}
|
||||
|
||||
static int
|
||||
amr_setup_mbox(struct amr_softc *sc)
|
||||
{
|
||||
int error;
|
||||
void *p;
|
||||
uint32_t baddr;
|
||||
|
||||
debug_called(1);
|
||||
|
||||
@ -666,13 +665,55 @@ amr_setup_mbox(struct amr_softc *sc)
|
||||
return(ENOMEM);
|
||||
}
|
||||
bus_dmamap_load(sc->amr_mailbox_dmat, sc->amr_mailbox_dmamap, p,
|
||||
sizeof(struct amr_mailbox64), amr_setup_mbox_helper, sc, 0);
|
||||
sizeof(struct amr_mailbox64), amr_sglist_helper, &baddr, 0);
|
||||
/*
|
||||
* Conventional mailbox is inside the mailbox64 region.
|
||||
*/
|
||||
/* save physical base of the basic mailbox structure */
|
||||
sc->amr_mailboxphys = baddr + offsetof(struct amr_mailbox64, mb);
|
||||
bzero(p, sizeof(struct amr_mailbox64));
|
||||
sc->amr_mailbox64 = (struct amr_mailbox64 *)p;
|
||||
sc->amr_mailbox = &sc->amr_mailbox64->mb;
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int
|
||||
amr_ccb_map(struct amr_softc *sc)
|
||||
{
|
||||
int ccbsize, error;
|
||||
|
||||
/*
|
||||
* Passthrough and Extended passthrough structures will share the same
|
||||
* memory.
|
||||
*/
|
||||
ccbsize = sizeof(union amr_ccb) * AMR_MAXCMD;
|
||||
error = bus_dma_tag_create(sc->amr_parent_dmat, /* parent */
|
||||
128, 0, /* alignment,boundary */
|
||||
BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
|
||||
BUS_SPACE_MAXADDR, /* highaddr */
|
||||
NULL, NULL, /* filter, filterarg */
|
||||
ccbsize, /* maxsize */
|
||||
1, /* nsegments */
|
||||
ccbsize, /* maxsegsize */
|
||||
0, /* flags */
|
||||
NULL, NULL, /* lockfunc, lockarg */
|
||||
&sc->amr_ccb_dmat);
|
||||
if (error != 0) {
|
||||
device_printf(sc->amr_dev, "can't allocate ccb tag\n");
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
error = bus_dmamem_alloc(sc->amr_ccb_dmat, (void **)&sc->amr_ccb,
|
||||
BUS_DMA_NOWAIT, &sc->amr_ccb_dmamap);
|
||||
if (error) {
|
||||
device_printf(sc->amr_dev, "can't allocate ccb memory\n");
|
||||
return (ENOMEM);
|
||||
}
|
||||
bus_dmamap_load(sc->amr_ccb_dmat, sc->amr_ccb_dmamap, sc->amr_ccb,
|
||||
ccbsize, amr_sglist_helper, &sc->amr_ccb_busaddr, 0);
|
||||
bzero(sc->amr_ccb, ccbsize);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -100,6 +100,12 @@ struct amr_logdrive
|
||||
|
||||
#define AMR_CMD_CLUSTERSIZE (16 * 1024)
|
||||
|
||||
union amr_ccb {
|
||||
struct amr_passthrough ccb_pthru;
|
||||
struct amr_ext_passthrough ccb_epthru;
|
||||
uint8_t bytes[128];
|
||||
};
|
||||
|
||||
/*
|
||||
* Per-command control structure.
|
||||
*/
|
||||
@ -121,8 +127,7 @@ struct amr_command
|
||||
int ac_flags;
|
||||
#define AMR_CMD_DATAIN (1<<0)
|
||||
#define AMR_CMD_DATAOUT (1<<1)
|
||||
#define AMR_CMD_CCB_DATAIN (1<<2)
|
||||
#define AMR_CMD_CCB_DATAOUT (1<<3)
|
||||
#define AMR_CMD_CCB (1<<2)
|
||||
#define AMR_CMD_PRIORITY (1<<4)
|
||||
#define AMR_CMD_MAPPED (1<<5)
|
||||
#define AMR_CMD_SLEEP (1<<6)
|
||||
@ -139,11 +144,13 @@ struct amr_command
|
||||
bus_dmamap_t ac_dmamap;
|
||||
bus_dmamap_t ac_dma64map;
|
||||
|
||||
void *ac_ccb_data;
|
||||
size_t ac_ccb_length;
|
||||
bus_dmamap_t ac_ccb_dmamap;
|
||||
bus_dmamap_t ac_ccb_dma64map;
|
||||
bus_dma_tag_t ac_tag;
|
||||
bus_dmamap_t ac_datamap;
|
||||
int ac_nsegments;
|
||||
uint32_t ac_mb_physaddr;
|
||||
|
||||
union amr_ccb *ac_ccb;
|
||||
uint32_t ac_ccb_busaddr;
|
||||
};
|
||||
|
||||
struct amr_command_cluster
|
||||
@ -185,6 +192,11 @@ struct amr_softc
|
||||
bus_dma_tag_t amr_sg_dmat; /* s/g buffer DMA tag */
|
||||
bus_dmamap_t amr_sg_dmamap; /* map for s/g buffers */
|
||||
|
||||
union amr_ccb *amr_ccb;
|
||||
uint32_t amr_ccb_busaddr;
|
||||
bus_dma_tag_t amr_ccb_dmat;
|
||||
bus_dmamap_t amr_ccb_dmamap;
|
||||
|
||||
/* controller limits and features */
|
||||
int amr_nextslot; /* Next slot to use for newly allocated commands */
|
||||
int amr_maxio; /* maximum number of I/O transactions */
|
||||
|
Loading…
x
Reference in New Issue
Block a user