static int sbp2util_create_command_orb_pool(struct sbp2_lu *lu)
{
- struct sbp2_fwhost_info *hi = lu->hi;
struct sbp2_command_info *cmd;
+ struct device *dmadev = lu->hi->host->device.parent;
int i, orbs = sbp2_serialize_io ? 2 : SBP2_MAX_CMDS;
for (i = 0; i < orbs; i++) {
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd)
- return -ENOMEM;
- cmd->command_orb_dma = dma_map_single(hi->host->device.parent,
- &cmd->command_orb,
- sizeof(struct sbp2_command_orb),
- DMA_TO_DEVICE);
- cmd->sge_dma = dma_map_single(hi->host->device.parent,
- &cmd->scatter_gather_element,
- sizeof(cmd->scatter_gather_element),
- DMA_TO_DEVICE);
+ goto failed_alloc;
+
+ cmd->command_orb_dma =
+ dma_map_single(dmadev, &cmd->command_orb,
+ sizeof(struct sbp2_command_orb),
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(dmadev, cmd->command_orb_dma))
+ goto failed_orb;
+
+ cmd->sge_dma =
+ dma_map_single(dmadev, &cmd->scatter_gather_element,
+ sizeof(cmd->scatter_gather_element),
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(dmadev, cmd->sge_dma))
+ goto failed_sge;
+
INIT_LIST_HEAD(&cmd->list);
list_add_tail(&cmd->list, &lu->cmd_orb_completed);
}
return 0;
+
+failed_sge:
+ dma_unmap_single(dmadev, cmd->command_orb_dma,
+ sizeof(struct sbp2_command_orb), DMA_TO_DEVICE);
+failed_orb:
+ kfree(cmd);
+failed_alloc:
+ return -ENOMEM;
}
static void sbp2util_remove_command_orb_pool(struct sbp2_lu *lu,
return 0;
}
-static void sbp2_prep_command_orb_sg(struct sbp2_command_orb *orb,
- struct sbp2_fwhost_info *hi,
- struct sbp2_command_info *cmd,
- unsigned int scsi_use_sg,
- struct scatterlist *sg,
- u32 orb_direction,
- enum dma_data_direction dma_dir)
+static int sbp2_prep_command_orb_sg(struct sbp2_command_orb *orb,
+ struct sbp2_fwhost_info *hi,
+ struct sbp2_command_info *cmd,
+ unsigned int scsi_use_sg,
+ struct scatterlist *sg,
+ u32 orb_direction,
+ enum dma_data_direction dma_dir)
{
+ struct device *dmadev = hi->host->device.parent;
+
cmd->dma_dir = dma_dir;
orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
orb->misc |= ORB_SET_DIRECTION(orb_direction);
cmd->dma_size = sg->length;
cmd->dma_type = CMD_DMA_PAGE;
- cmd->cmd_dma = dma_map_page(hi->host->device.parent,
- sg_page(sg), sg->offset,
+ cmd->cmd_dma = dma_map_page(dmadev, sg_page(sg), sg->offset,
cmd->dma_size, cmd->dma_dir);
+ if (dma_mapping_error(dmadev, cmd->cmd_dma)) {
+ cmd->cmd_dma = 0;
+ return -ENOMEM;
+ }
orb->data_descriptor_lo = cmd->cmd_dma;
orb->misc |= ORB_SET_DATA_SIZE(cmd->dma_size);
&cmd->scatter_gather_element[0];
u32 sg_count, sg_len;
dma_addr_t sg_addr;
- int i, count = dma_map_sg(hi->host->device.parent, sg,
- scsi_use_sg, dma_dir);
+ int i, count = dma_map_sg(dmadev, sg, scsi_use_sg, dma_dir);
cmd->dma_size = scsi_use_sg;
cmd->sge_buffer = sg;
orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1);
orb->data_descriptor_lo = cmd->sge_dma;
+ dma_sync_single_for_cpu(dmadev, cmd->sge_dma,
+ sizeof(cmd->scatter_gather_element),
+ DMA_TO_DEVICE);
+
/* loop through and fill out our SBP-2 page tables
* (and split up anything too large) */
for (i = 0, sg_count = 0; i < count; i++, sg = sg_next(sg)) {
sbp2util_cpu_to_be32_buffer(sg_element,
(sizeof(struct sbp2_unrestricted_page_table)) *
sg_count);
+
+ dma_sync_single_for_device(dmadev, cmd->sge_dma,
+ sizeof(cmd->scatter_gather_element),
+ DMA_TO_DEVICE);
}
+ return 0;
}
-static void sbp2_create_command_orb(struct sbp2_lu *lu,
- struct sbp2_command_info *cmd,
- struct scsi_cmnd *SCpnt)
+static int sbp2_create_command_orb(struct sbp2_lu *lu,
+ struct sbp2_command_info *cmd,
+ struct scsi_cmnd *SCpnt)
{
- struct sbp2_fwhost_info *hi = lu->hi;
+ struct device *dmadev = lu->hi->host->device.parent;
struct sbp2_command_orb *orb = &cmd->command_orb;
- u32 orb_direction;
unsigned int scsi_request_bufflen = scsi_bufflen(SCpnt);
enum dma_data_direction dma_dir = SCpnt->sc_data_direction;
+ u32 orb_direction;
+ int ret;
+ dma_sync_single_for_cpu(dmadev, cmd->command_orb_dma,
+ sizeof(struct sbp2_command_orb), DMA_TO_DEVICE);
/*
* Set-up our command ORB.
*
orb->data_descriptor_hi = 0x0;
orb->data_descriptor_lo = 0x0;
orb->misc |= ORB_SET_DIRECTION(1);
- } else
- sbp2_prep_command_orb_sg(orb, hi, cmd, scsi_sg_count(SCpnt),
- scsi_sglist(SCpnt),
- orb_direction, dma_dir);
-
+ ret = 0;
+ } else {
+ ret = sbp2_prep_command_orb_sg(orb, lu->hi, cmd,
+ scsi_sg_count(SCpnt),
+ scsi_sglist(SCpnt),
+ orb_direction, dma_dir);
+ }
sbp2util_cpu_to_be32_buffer(orb, sizeof(*orb));
memset(orb->cdb, 0, sizeof(orb->cdb));
memcpy(orb->cdb, SCpnt->cmnd, SCpnt->cmd_len);
+
+ dma_sync_single_for_device(dmadev, cmd->command_orb_dma,
+ sizeof(struct sbp2_command_orb), DMA_TO_DEVICE);
+ return ret;
}
static void sbp2_link_orb_command(struct sbp2_lu *lu,
size_t length;
unsigned long flags;
- dma_sync_single_for_device(hi->host->device.parent,
- cmd->command_orb_dma,
- sizeof(struct sbp2_command_orb),
- DMA_TO_DEVICE);
- dma_sync_single_for_device(hi->host->device.parent, cmd->sge_dma,
- sizeof(cmd->scatter_gather_element),
- DMA_TO_DEVICE);
-
/* check to see if there are any previous orbs to use */
spin_lock_irqsave(&lu->cmd_orb_lock, flags);
last_orb = lu->last_orb;
if (!cmd)
return -EIO;
- sbp2_create_command_orb(lu, cmd, SCpnt);
- sbp2_link_orb_command(lu, cmd);
+ if (sbp2_create_command_orb(lu, cmd, SCpnt))
+ return -ENOMEM;
+ sbp2_link_orb_command(lu, cmd);
return 0;
}
else
cmd = sbp2util_find_command_for_orb(lu, sb->ORB_offset_lo);
if (cmd) {
- dma_sync_single_for_cpu(hi->host->device.parent,
- cmd->command_orb_dma,
- sizeof(struct sbp2_command_orb),
- DMA_TO_DEVICE);
- dma_sync_single_for_cpu(hi->host->device.parent, cmd->sge_dma,
- sizeof(cmd->scatter_gather_element),
- DMA_TO_DEVICE);
/* Grab SCSI command pointers and check status. */
/*
* FIXME: If the src field in the status is 1, the ORB DMA must
static void sbp2scsi_complete_all_commands(struct sbp2_lu *lu, u32 status)
{
- struct sbp2_fwhost_info *hi = lu->hi;
struct list_head *lh;
struct sbp2_command_info *cmd;
unsigned long flags;
while (!list_empty(&lu->cmd_orb_inuse)) {
lh = lu->cmd_orb_inuse.next;
cmd = list_entry(lh, struct sbp2_command_info, list);
- dma_sync_single_for_cpu(hi->host->device.parent,
- cmd->command_orb_dma,
- sizeof(struct sbp2_command_orb),
- DMA_TO_DEVICE);
- dma_sync_single_for_cpu(hi->host->device.parent, cmd->sge_dma,
- sizeof(cmd->scatter_gather_element),
- DMA_TO_DEVICE);
sbp2util_mark_command_completed(lu, cmd);
if (cmd->Current_SCpnt) {
cmd->Current_SCpnt->result = status << 16;
static int sbp2scsi_abort(struct scsi_cmnd *SCpnt)
{
struct sbp2_lu *lu = (struct sbp2_lu *)SCpnt->device->host->hostdata[0];
- struct sbp2_fwhost_info *hi = lu->hi;
struct sbp2_command_info *cmd;
unsigned long flags;
spin_lock_irqsave(&lu->cmd_orb_lock, flags);
cmd = sbp2util_find_command_for_SCpnt(lu, SCpnt);
if (cmd) {
- dma_sync_single_for_cpu(hi->host->device.parent,
- cmd->command_orb_dma,
- sizeof(struct sbp2_command_orb),
- DMA_TO_DEVICE);
- dma_sync_single_for_cpu(hi->host->device.parent,
- cmd->sge_dma,
- sizeof(cmd->scatter_gather_element),
- DMA_TO_DEVICE);
sbp2util_mark_command_completed(lu, cmd);
if (cmd->Current_SCpnt) {
cmd->Current_SCpnt->result = DID_ABORT << 16;