From f70575805708cabdedea7498aaa3f710fde4d920 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Wed, 31 Jan 2024 03:29:01 +0000
Subject: [PATCH] add lvds1024*800

---
 kernel/drivers/scsi/wd719x.c |  177 ++++++++++++++++++++++++++++++----------------------------
 1 files changed, 91 insertions(+), 86 deletions(-)

diff --git a/kernel/drivers/scsi/wd719x.c b/kernel/drivers/scsi/wd719x.c
index 974bfb3..edc8a13 100644
--- a/kernel/drivers/scsi/wd719x.c
+++ b/kernel/drivers/scsi/wd719x.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * Driver for Western Digital WD7193, WD7197 and WD7296 SCSI cards
  * Copyright 2013 Ondrej Zary
@@ -107,8 +108,15 @@
 	}
 
 	if (status != WD719X_INT_NOERRORS) {
+		u8 sue = wd719x_readb(wd, WD719X_AMR_SCB_ERROR);
+		/* we get this after wd719x_dev_reset, it's not an error */
+		if (sue == WD719X_SUE_TERM)
+			return 0;
+		/* we get this after wd719x_bus_reset, it's not an error */
+		if (sue == WD719X_SUE_RESET)
+			return 0;
 		dev_err(&wd->pdev->dev, "direct command failed, status 0x%02x, SUE 0x%02x\n",
-			status, wd719x_readb(wd, WD719X_AMR_SCB_ERROR));
+			status, sue);
 		return -EIO;
 	}
 
@@ -127,8 +135,10 @@
 	if (wd719x_wait_ready(wd))
 		return -ETIMEDOUT;
 
-	/* make sure we get NO interrupts */
-	dev |= WD719X_DISABLE_INT;
+	/* disable interrupts except for RESET/ABORT (it breaks them) */
+	if (opcode != WD719X_CMD_BUSRESET && opcode != WD719X_CMD_ABORT &&
+	    opcode != WD719X_CMD_ABORT_TAG && opcode != WD719X_CMD_RESET)
+		dev |= WD719X_DISABLE_INT;
 	wd719x_writeb(wd, WD719X_AMR_CMD_PARAM, dev);
 	wd719x_writeb(wd, WD719X_AMR_CMD_PARAM_2, lun);
 	wd719x_writeb(wd, WD719X_AMR_CMD_PARAM_3, tag);
@@ -153,8 +163,6 @@
 
 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 +170,35 @@
 	/* 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 +208,10 @@
 {
 	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 +220,19 @@
 	/* 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 +247,8 @@
 
 	/* 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,11 +269,15 @@
 		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);
@@ -295,7 +285,17 @@
 	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 +327,8 @@
 	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 +464,7 @@
 {
 	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);
@@ -474,6 +474,7 @@
 	spin_lock_irqsave(wd->sh->host_lock, flags);
 	result = wd719x_direct_cmd(wd, action, cmd->device->id,
 				   cmd->device->lun, cmd->tag, scb->phys, 0);
+	wd719x_finish_cmd(scb, DID_ABORT);
 	spin_unlock_irqrestore(wd->sh->host_lock, flags);
 	if (result)
 		return FAILED;
@@ -486,6 +487,7 @@
 	int result;
 	unsigned long flags;
 	struct wd719x *wd = shost_priv(cmd->device->host);
+	struct wd719x_scb *scb, *tmp;
 
 	dev_info(&wd->pdev->dev, "%s reset requested\n",
 		 (opcode == WD719X_CMD_BUSRESET) ? "bus" : "device");
@@ -493,6 +495,12 @@
 	spin_lock_irqsave(wd->sh->host_lock, flags);
 	result = wd719x_direct_cmd(wd, opcode, device, 0, 0, 0,
 				   WD719X_WAIT_FOR_SCSI_RESET);
+	/* flush all SCBs (or all for a device if dev_reset) */
+	list_for_each_entry_safe(scb, tmp, &wd->active_scbs, list) {
+		if (opcode == WD719X_CMD_BUSRESET ||
+		    scb->cmd->device->id == device)
+			wd719x_finish_cmd(scb, DID_RESET);
+	}
 	spin_unlock_irqrestore(wd->sh->host_lock, flags);
 	if (result)
 		return FAILED;
@@ -515,24 +523,23 @@
 	struct wd719x *wd = shost_priv(cmd->device->host);
 	struct wd719x_scb *scb, *tmp;
 	unsigned long flags;
-	int result;
 
 	dev_info(&wd->pdev->dev, "host reset requested\n");
 	spin_lock_irqsave(wd->sh->host_lock, flags);
-	/* Try to reinit the RISC */
-	if (wd719x_chip_init(wd) == 0)
-		result = SUCCESS;
-	else
-		result = FAILED;
+	/* stop the RISC */
+	if (wd719x_direct_cmd(wd, WD719X_CMD_SLEEP, 0, 0, 0, 0,
+			      WD719X_WAIT_FOR_RISC))
+		dev_warn(&wd->pdev->dev, "RISC sleep command failed\n");
+	/* disable RISC */
+	wd719x_writeb(wd, WD719X_PCI_MODE_SELECT, 0);
 
 	/* 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, DID_RESET);
 	spin_unlock_irqrestore(wd->sh->host_lock, flags);
 
-	return result;
+	/* Try to reinit the RISC */
+	return wd719x_chip_init(wd) == 0 ? SUCCESS : FAILED;
 }
 
 static int wd719x_biosparam(struct scsi_device *sdev, struct block_device *bdev,
@@ -555,7 +562,6 @@
 					union wd719x_regs regs,
 					struct wd719x_scb *scb)
 {
-	struct scsi_cmnd *cmd;
 	int result;
 
 	/* now have to find result from card */
@@ -643,9 +649,8 @@
 		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)
@@ -686,7 +691,7 @@
 			else
 				dev_err(&wd->pdev->dev, "card returned invalid SCB pointer\n");
 		} else
-			dev_warn(&wd->pdev->dev, "direct command 0x%x completed\n",
+			dev_dbg(&wd->pdev->dev, "direct command 0x%x completed\n",
 				 regs.bytes.OPC);
 		break;
 	case WD719X_INT_PIOREADY:
@@ -809,7 +814,6 @@
 	int ret;
 
 	INIT_LIST_HEAD(&wd->active_scbs);
-	INIT_LIST_HEAD(&wd->free_scbs);
 
 	sh->base = pci_resource_start(wd->pdev, 0);
 
@@ -820,17 +824,18 @@
 	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 +867,10 @@
 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 +879,7 @@
 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 +890,6 @@
 	.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 +902,7 @@
 	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;
 	}

--
Gitblit v1.6.2