[PATCH 2/3] wd719x: use per-command private data

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add the SCB onto the scsi command allocation and use dma streaming
mappings for it only when in use.  This avoid possibly calling
dma_alloc_coherent under a lock or even in irq context, while also
making the code simpler.

Signed-off-by: Christoph Hellwig <hch@xxxxxx>
---
 drivers/scsi/wd719x.c | 95 ++++++++++++++++++-------------------------
 drivers/scsi/wd719x.h |  1 -
 2 files changed, 39 insertions(+), 57 deletions(-)

diff --git a/drivers/scsi/wd719x.c b/drivers/scsi/wd719x.c
index 7b05bbcfb186..d47190f08ed6 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))
@@ -164,10 +162,6 @@ static void wd719x_destroy(struct wd719x *wd)
 
 	WARN_ON_ONCE(!list_empty(&wd->active_scbs));
 
-	/* free all SCBs */
-	list_for_each_entry(scb, &wd->free_scbs, list)
-		pci_free_consistent(wd->pdev, sizeof(struct wd719x_scb), scb,
-				    scb->phys);
 	/* free internal buffers */
 	pci_free_consistent(wd->pdev, wd->fw_size, wd->fw_virt, wd->fw_phys);
 	wd->fw_virt = NULL;
@@ -180,18 +174,20 @@ static void wd719x_destroy(struct wd719x *wd)
 	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_TO_DEVICE);
+	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);
 }
@@ -201,36 +197,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;
@@ -243,6 +213,8 @@ static int wd719x_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
 	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_error;
 	scb->sense_buf = cpu_to_le32(cmd->SCp.dma_handle);
 
 	/* request autosense */
@@ -257,11 +229,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) {
@@ -277,24 +246,42 @@ static int wd719x_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
 			scb->sg_list[i].length = cpu_to_le32(sg_dma_len(sg));
 		}
 		scb->SCB_options |= WD719X_SCB_FLAGS_DO_SCATTER_GATHER;
+
+		scb->phys = dma_map_single(&wd->pdev->dev, scb, sizeof(*scb),
+					   DMA_TO_DEVICE);
+		if (dma_mapping_error(&wd->pdev->dev, scb->phys))
+			goto out_unmap_scsi_cmd;
 	} else { /* zero length */
 		scb->data_length = 0;
 		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_scsi_cmd:
+	scsi_dma_unmap(cmd);
+out_unmap_sense:
+	dma_unmap_single(&wd->pdev->dev, cmd->SCp.dma_handle,
+			 SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
+out_error:
+	cmd->result = DID_ERROR << 16;
+	cmd->scsi_done(cmd);
 	return 0;
 }
 
@@ -463,7 +450,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);
@@ -525,10 +512,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;
@@ -554,7 +539,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 */
@@ -642,9 +626,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)
@@ -808,7 +791,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);
 
@@ -873,6 +855,7 @@ static int wd719x_board_found(struct Scsi_Host *sh)
 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,
diff --git a/drivers/scsi/wd719x.h b/drivers/scsi/wd719x.h
index 0455b1633ca7..abaabd419a54 100644
--- a/drivers/scsi/wd719x.h
+++ b/drivers/scsi/wd719x.h
@@ -74,7 +74,6 @@ struct wd719x {
 	void *hash_virt;	/* hash table CPU address */
 	dma_addr_t hash_phys;	/* hash table bus address */
 	struct list_head active_scbs;
-	struct list_head free_scbs;
 };
 
 /* timeout delays in microsecs */
-- 
2.19.1




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]

  Powered by Linux