summaryrefslogtreecommitdiff
path: root/drivers/scsi/wd719x.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/wd719x.c')
-rw-r--r--drivers/scsi/wd719x.c136
1 files changed, 61 insertions, 75 deletions
diff --git a/drivers/scsi/wd719x.c b/drivers/scsi/wd719x.c
index 974bfb3f30f4..e3310e9488d2 100644
--- a/drivers/scsi/wd719x.c
+++ b/drivers/scsi/wd719x.c
@@ -153,8 +153,6 @@ static int wd719x_direct_cmd(struct wd719x *wd, u8 opcode, u8 dev, u8 lun,
static void wd719x_destroy(struct wd719x *wd)
{
- struct wd719x_scb *scb;
-
/* stop the RISC */
if (wd719x_direct_cmd(wd, WD719X_CMD_SLEEP, 0, 0, 0, 0,
WD719X_WAIT_FOR_RISC))
@@ -162,37 +160,35 @@ static void wd719x_destroy(struct wd719x *wd)
/* disable RISC */
wd719x_writeb(wd, WD719X_PCI_MODE_SELECT, 0);
- /* free all SCBs */
- list_for_each_entry(scb, &wd->active_scbs, list)
- pci_free_consistent(wd->pdev, sizeof(struct wd719x_scb), scb,
- scb->phys);
- list_for_each_entry(scb, &wd->free_scbs, list)
- pci_free_consistent(wd->pdev, sizeof(struct wd719x_scb), scb,
- scb->phys);
+ WARN_ON_ONCE(!list_empty(&wd->active_scbs));
+
/* free internal buffers */
- pci_free_consistent(wd->pdev, wd->fw_size, wd->fw_virt, wd->fw_phys);
+ dma_free_coherent(&wd->pdev->dev, wd->fw_size, wd->fw_virt,
+ wd->fw_phys);
wd->fw_virt = NULL;
- pci_free_consistent(wd->pdev, WD719X_HASH_TABLE_SIZE, wd->hash_virt,
- wd->hash_phys);
+ dma_free_coherent(&wd->pdev->dev, WD719X_HASH_TABLE_SIZE, wd->hash_virt,
+ wd->hash_phys);
wd->hash_virt = NULL;
- pci_free_consistent(wd->pdev, sizeof(struct wd719x_host_param),
- wd->params, wd->params_phys);
+ dma_free_coherent(&wd->pdev->dev, sizeof(struct wd719x_host_param),
+ wd->params, wd->params_phys);
wd->params = NULL;
free_irq(wd->pdev->irq, wd);
}
-/* finish a SCSI command, mark SCB (if any) as free, unmap buffers */
-static void wd719x_finish_cmd(struct scsi_cmnd *cmd, int result)
+/* finish a SCSI command, unmap buffers */
+static void wd719x_finish_cmd(struct wd719x_scb *scb, int result)
{
+ struct scsi_cmnd *cmd = scb->cmd;
struct wd719x *wd = shost_priv(cmd->device->host);
- struct wd719x_scb *scb = (struct wd719x_scb *) cmd->host_scribble;
- if (scb) {
- list_move(&scb->list, &wd->free_scbs);
- dma_unmap_single(&wd->pdev->dev, cmd->SCp.dma_handle,
- SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
- scsi_dma_unmap(cmd);
- }
+ list_del(&scb->list);
+
+ dma_unmap_single(&wd->pdev->dev, scb->phys,
+ sizeof(struct wd719x_scb), DMA_BIDIRECTIONAL);
+ scsi_dma_unmap(cmd);
+ dma_unmap_single(&wd->pdev->dev, cmd->SCp.dma_handle,
+ SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
+
cmd->result = result << 16;
cmd->scsi_done(cmd);
}
@@ -202,36 +198,10 @@ static int wd719x_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
{
int i, count_sg;
unsigned long flags;
- struct wd719x_scb *scb;
+ struct wd719x_scb *scb = scsi_cmd_priv(cmd);
struct wd719x *wd = shost_priv(sh);
- dma_addr_t phys;
- cmd->host_scribble = NULL;
-
- /* get a free SCB - either from existing ones or allocate a new one */
- spin_lock_irqsave(wd->sh->host_lock, flags);
- scb = list_first_entry_or_null(&wd->free_scbs, struct wd719x_scb, list);
- if (scb) {
- list_del(&scb->list);
- phys = scb->phys;
- } else {
- spin_unlock_irqrestore(wd->sh->host_lock, flags);
- scb = pci_alloc_consistent(wd->pdev, sizeof(struct wd719x_scb),
- &phys);
- spin_lock_irqsave(wd->sh->host_lock, flags);
- if (!scb) {
- dev_err(&wd->pdev->dev, "unable to allocate SCB\n");
- wd719x_finish_cmd(cmd, DID_ERROR);
- spin_unlock_irqrestore(wd->sh->host_lock, flags);
- return 0;
- }
- }
- memset(scb, 0, sizeof(struct wd719x_scb));
- list_add(&scb->list, &wd->active_scbs);
-
- scb->phys = phys;
scb->cmd = cmd;
- cmd->host_scribble = (char *) scb;
scb->CDB_tag = 0; /* Tagged queueing not supported yet */
scb->devid = cmd->device->id;
@@ -240,10 +210,19 @@ static int wd719x_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
/* copy the command */
memcpy(scb->CDB, cmd->cmnd, cmd->cmd_len);
+ /* map SCB */
+ scb->phys = dma_map_single(&wd->pdev->dev, scb, sizeof(*scb),
+ DMA_BIDIRECTIONAL);
+
+ if (dma_mapping_error(&wd->pdev->dev, scb->phys))
+ goto out_error;
+
/* map sense buffer */
scb->sense_buf_length = SCSI_SENSE_BUFFERSIZE;
cmd->SCp.dma_handle = dma_map_single(&wd->pdev->dev, cmd->sense_buffer,
SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
+ if (dma_mapping_error(&wd->pdev->dev, cmd->SCp.dma_handle))
+ goto out_unmap_scb;
scb->sense_buf = cpu_to_le32(cmd->SCp.dma_handle);
/* request autosense */
@@ -258,11 +237,8 @@ static int wd719x_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
/* Scather/gather */
count_sg = scsi_dma_map(cmd);
- if (count_sg < 0) {
- wd719x_finish_cmd(cmd, DID_ERROR);
- spin_unlock_irqrestore(wd->sh->host_lock, flags);
- return 0;
- }
+ if (count_sg < 0)
+ goto out_unmap_sense;
BUG_ON(count_sg > WD719X_SG);
if (count_sg) {
@@ -283,19 +259,33 @@ static int wd719x_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
scb->data_p = 0;
}
+ spin_lock_irqsave(wd->sh->host_lock, flags);
+
/* check if the Command register is free */
if (wd719x_readb(wd, WD719X_AMR_COMMAND) != WD719X_CMD_READY) {
spin_unlock_irqrestore(wd->sh->host_lock, flags);
return SCSI_MLQUEUE_HOST_BUSY;
}
+ list_add(&scb->list, &wd->active_scbs);
+
/* write pointer to the AMR */
wd719x_writel(wd, WD719X_AMR_SCB_IN, scb->phys);
/* send SCB opcode */
wd719x_writeb(wd, WD719X_AMR_COMMAND, WD719X_CMD_PROCESS_SCB);
spin_unlock_irqrestore(wd->sh->host_lock, flags);
+ return 0;
+out_unmap_sense:
+ dma_unmap_single(&wd->pdev->dev, cmd->SCp.dma_handle,
+ SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
+out_unmap_scb:
+ dma_unmap_single(&wd->pdev->dev, scb->phys, sizeof(*scb),
+ DMA_BIDIRECTIONAL);
+out_error:
+ cmd->result = DID_ERROR << 16;
+ cmd->scsi_done(cmd);
return 0;
}
@@ -327,8 +317,8 @@ static int wd719x_chip_init(struct wd719x *wd)
wd->fw_size = ALIGN(fw_wcs->size, 4) + fw_risc->size;
if (!wd->fw_virt)
- wd->fw_virt = pci_alloc_consistent(wd->pdev, wd->fw_size,
- &wd->fw_phys);
+ wd->fw_virt = dma_alloc_coherent(&wd->pdev->dev, wd->fw_size,
+ &wd->fw_phys, GFP_KERNEL);
if (!wd->fw_virt) {
ret = -ENOMEM;
goto wd719x_init_end;
@@ -464,7 +454,7 @@ static int wd719x_abort(struct scsi_cmnd *cmd)
{
int action, result;
unsigned long flags;
- struct wd719x_scb *scb = (struct wd719x_scb *)cmd->host_scribble;
+ struct wd719x_scb *scb = scsi_cmd_priv(cmd);
struct wd719x *wd = shost_priv(cmd->device->host);
dev_info(&wd->pdev->dev, "abort command, tag: %x\n", cmd->tag);
@@ -526,10 +516,8 @@ static int wd719x_host_reset(struct scsi_cmnd *cmd)
result = FAILED;
/* flush all SCBs */
- list_for_each_entry_safe(scb, tmp, &wd->active_scbs, list) {
- struct scsi_cmnd *tmp_cmd = scb->cmd;
- wd719x_finish_cmd(tmp_cmd, result);
- }
+ list_for_each_entry_safe(scb, tmp, &wd->active_scbs, list)
+ wd719x_finish_cmd(scb, result);
spin_unlock_irqrestore(wd->sh->host_lock, flags);
return result;
@@ -555,7 +543,6 @@ static inline void wd719x_interrupt_SCB(struct wd719x *wd,
union wd719x_regs regs,
struct wd719x_scb *scb)
{
- struct scsi_cmnd *cmd;
int result;
/* now have to find result from card */
@@ -643,9 +630,8 @@ static inline void wd719x_interrupt_SCB(struct wd719x *wd,
result = DID_ERROR;
break;
}
- cmd = scb->cmd;
- wd719x_finish_cmd(cmd, result);
+ wd719x_finish_cmd(scb, result);
}
static irqreturn_t wd719x_interrupt(int irq, void *dev_id)
@@ -809,7 +795,6 @@ static int wd719x_board_found(struct Scsi_Host *sh)
int ret;
INIT_LIST_HEAD(&wd->active_scbs);
- INIT_LIST_HEAD(&wd->free_scbs);
sh->base = pci_resource_start(wd->pdev, 0);
@@ -820,17 +805,18 @@ static int wd719x_board_found(struct Scsi_Host *sh)
wd->fw_virt = NULL;
/* memory area for host (EEPROM) parameters */
- wd->params = pci_alloc_consistent(wd->pdev,
- sizeof(struct wd719x_host_param),
- &wd->params_phys);
+ wd->params = dma_alloc_coherent(&wd->pdev->dev,
+ sizeof(struct wd719x_host_param),
+ &wd->params_phys, GFP_KERNEL);
if (!wd->params) {
dev_warn(&wd->pdev->dev, "unable to allocate parameter buffer\n");
return -ENOMEM;
}
/* memory area for the RISC for hash table of outstanding requests */
- wd->hash_virt = pci_alloc_consistent(wd->pdev, WD719X_HASH_TABLE_SIZE,
- &wd->hash_phys);
+ wd->hash_virt = dma_alloc_coherent(&wd->pdev->dev,
+ WD719X_HASH_TABLE_SIZE,
+ &wd->hash_phys, GFP_KERNEL);
if (!wd->hash_virt) {
dev_warn(&wd->pdev->dev, "unable to allocate hash buffer\n");
ret = -ENOMEM;
@@ -862,10 +848,10 @@ static int wd719x_board_found(struct Scsi_Host *sh)
fail_free_irq:
free_irq(wd->pdev->irq, wd);
fail_free_hash:
- pci_free_consistent(wd->pdev, WD719X_HASH_TABLE_SIZE, wd->hash_virt,
+ dma_free_coherent(&wd->pdev->dev, WD719X_HASH_TABLE_SIZE, wd->hash_virt,
wd->hash_phys);
fail_free_params:
- pci_free_consistent(wd->pdev, sizeof(struct wd719x_host_param),
+ dma_free_coherent(&wd->pdev->dev, sizeof(struct wd719x_host_param),
wd->params, wd->params_phys);
return ret;
@@ -874,6 +860,7 @@ fail_free_params:
static struct scsi_host_template wd719x_template = {
.module = THIS_MODULE,
.name = "Western Digital 719x",
+ .cmd_size = sizeof(struct wd719x_scb),
.queuecommand = wd719x_queuecommand,
.eh_abort_handler = wd719x_abort,
.eh_device_reset_handler = wd719x_dev_reset,
@@ -884,7 +871,6 @@ static struct scsi_host_template wd719x_template = {
.can_queue = 255,
.this_id = 7,
.sg_tablesize = WD719X_SG,
- .use_clustering = ENABLE_CLUSTERING,
};
static int wd719x_pci_probe(struct pci_dev *pdev, const struct pci_device_id *d)
@@ -897,7 +883,7 @@ static int wd719x_pci_probe(struct pci_dev *pdev, const struct pci_device_id *d)
if (err)
goto fail;
- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
+ if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) {
dev_warn(&pdev->dev, "Unable to set 32-bit DMA mask\n");
goto disable_device;
}