mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Clear.Zhang@uli.com.tw
To: Jeff Garzik <jgarzik@pobox.com>
Cc: linux-kernel@vger.kernel.org, linux-ide@vger.kernel.org,
	andrebalsa@mailingaddress.org, Peer.Chen@uli.com.tw,
	Emily.Jiang@uli.com.tw, Eric.Lo@uli.com.tw
Subject: re: Re: [patch] scsi/libata: correct bug for ULi M5281
Date: Tue, 14 Dec 2004 14:36:17 +0800	[thread overview]
Message-ID: <OF1118CDDC.A4BA64D4-ON48256F6A.0023C04B@uli.com.tw> (raw)

[-- Attachment #1: Type: text/plain, Size: 2378 bytes --]


Hi Jeff,

I've correct the patch according to your suggestion.
But we need libata-core.c to export some functions.
Here is the patch. Please check it and apply it to new kernels.
Thanks a lot.

Regards,
Clear                         (See attached file: patch_ULi_M5281)


                                                                                                                                
                      Jeff Garzik                                                                                               
                      <jgarzik@pobox.c         收件人: Clear.Zhang@uli.com.tw                                                  
                      om>                      抄送:   linux-kernel@vger.kernel.org, linux-ide@vger.kernel.org,                
                                               andrebalsa@mailingaddress.org, Peer.Chen@uli.com.tw, Emily.Jiang@uli.com.tw,     
                      2004-12-12 03:15         Eric.Lo@uli.com.tw                                                               
                                               主题:   Re: [patch] scsi/libata: correct bug for ULi M5281                      
                                                                                                                                



Clear.Zhang@uli.com.tw wrote:
> Hi, Jeff
>
> The sata_uli patch for m5281 looks fine,but some of M5281 chip's PHY
> is not stable sometime, so it need a workaround to correct the bug.
>
> patch_M5281workaround is just for it.
>
> The patch is applied to kernel 2.6.9. Pleases apply to new kernels,
thanks
> a lot.
>
> Signed-off-by: Clear Zhang <Clear.Zhang@uli.com.tw>

I'm afraid I must reject this patch.  We do not wish to put
hardware-specific workarounds in libata-core.c or libata-scsi.c.

I would suggest either
(a) finding a way to add the workaround to sata_uli.c, or
(b) finding the "root cause" of the problem, and determine why the
libata code is insufficient.

Two suggestions I have while investigating your problem:
1) Replacing the ->phy_reset() hook may allow you to solve the problem
in sata_uli.c.
2) It is entirely possible that we need to add additional error handling
code to libata, including hooks back into the low-level driver (such as
sata_uli.c).

Regards,

             Jeff






[-- Attachment #2: patch_ULi_M5281 --]
[-- Type: application/octet-stream, Size: 43421 bytes --]

diff -uprN linux-2.6.9-vanilla/drivers/scsi/libata-core.c linux-2.6.9/drivers/scsi/libata-core.c
--- linux-2.6.9-vanilla/drivers/scsi/libata-core.c	2004-10-19 05:53:06.000000000 +0800
+++ linux-2.6.9/drivers/scsi/libata-core.c	2004-12-14 14:08:00.202412224 +0800
@@ -3655,3 +3655,16 @@ EXPORT_SYMBOL_GPL(ata_scsi_release);
 EXPORT_SYMBOL_GPL(ata_host_intr);
 EXPORT_SYMBOL_GPL(ata_dev_classify);
 EXPORT_SYMBOL_GPL(ata_dev_id_string);
+EXPORT_SYMBOL_GPL(ata_scsi_rbuf_fill);
+EXPORT_SYMBOL_GPL(ata_scsiop_inq_00);
+EXPORT_SYMBOL_GPL(ata_scsiop_noop);
+EXPORT_SYMBOL_GPL(ata_scsi_badcmd);
+EXPORT_SYMBOL_GPL(ata_scsiop_inq_80);
+EXPORT_SYMBOL_GPL(ata_scsiop_inq_83);
+EXPORT_SYMBOL_GPL(ata_scsiop_mode_sense);
+EXPORT_SYMBOL_GPL(ata_scsiop_read_cap);
+EXPORT_SYMBOL_GPL(ata_scsiop_inq_std);
+EXPORT_SYMBOL_GPL(ata_to_sense_error);
+EXPORT_SYMBOL_GPL(ata_scsiop_report_luns);
+EXPORT_SYMBOL_GPL(ata_qc_new_init);
+EXPORT_SYMBOL_GPL(ata_qc_issue);
diff -uprN linux-2.6.9-vanilla/drivers/scsi/sata_uli.c linux-2.6.9/drivers/scsi/sata_uli.c
--- linux-2.6.9-vanilla/drivers/scsi/sata_uli.c	1970-01-01 08:00:00.000000000 +0800
+++ linux-2.6.9/drivers/scsi/sata_uli.c	2004-12-14 14:07:52.935516960 +0800
@@ -0,0 +1,1522 @@
+/*
+ *  sata_uli.c - ULi Electronics SATA
+ *
+ *  The contents of this file are subject to the Open
+ *  Software License version 1.1 that can be found at
+ *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+ *  by reference.
+ *
+ *  Alternatively, the contents of this file may be used under the terms
+ *  of the GNU General Public License version 2 (the "GPL") as distributed
+ *  in the kernel source COPYING file, in which case the provisions of
+ *  the GPL are applicable instead of the above.  If you wish to allow
+ *  the use of your version of this file only under the terms of the
+ *  GPL and not to allow others to use your version of this file under
+ *  the OSL, indicate your decision by deleting the provisions above and
+ *  replace them with the notice and other provisions required by the GPL.
+ *  If you do not delete the provisions above, a recipient may use your
+ *  version of this file under either the OSL or the GPL.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME	"sata_uli"
+#define DRV_VERSION	"0.11"
+
+//add by clear zhang 2004/12/13
+#define print_clear(_x_) printk _x_
+typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc, u8 *scsicmd);
+static u8 iftimeout=0;
+//end add
+
+enum {
+	uli_5289		= 0,
+	uli_5287		= 1,
+	uli_5281	       = 2,
+	
+	/* PCI configuration registers *///modiy by clear chung 2004/12/7
+	//ULI_SCR_BASE		= 0x90, /* sata0 phy SCR registers */
+	//ULI_SATA1_OFS		= 0x10, /* offset from sata0->sata1 phy regs */
+	ULI5287_BASE		 		 = 0x90, /* sata0 phy SCR registers */
+       	ULI5287_OFFS		 		 = 0x10, /* offset from sata0->sata1 phy regs */
+       	ULI5281_BASE		 		 = 0x60, /* sata0 phy SCR  registers */
+	ULI5281_OFFS		 		 = 0x60, /* offset from sata0->sata1 phy regs */
+
+};
+
+static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg);
+static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+
+//add by clear zhang 2004/12/13
+static struct ata_device *ata_scsi_find_dev_uli(struct ata_port *ap, struct scsi_device *scsidev);
+static unsigned int ata_scsi_flush_xlat_uli(struct ata_queued_cmd *qc, u8 *scsicmd);
+static unsigned int ata_scsi_verify_xlat_uli(struct ata_queued_cmd *qc, u8 *scsicmd);
+static unsigned int ata_scsi_rw_xlat_uli(struct ata_queued_cmd *qc, u8 *scsicmd);
+static inline ata_xlat_func_t ata_get_xlat_func_uli(struct ata_device *dev, u8 cmd);
+struct ata_queued_cmd *ata_scsi_qc_new_uli(struct ata_port *ap,
+				       struct ata_device *dev,
+				       struct scsi_cmnd *cmd,
+				       void (*done)(struct scsi_cmnd *));
+static int ata_scsi_qc_complete_uli(struct ata_queued_cmd *qc, u8 drv_stat);
+static void ata_scsi_translate_uli(struct ata_port *ap, struct ata_device *dev,
+			      struct scsi_cmnd *cmd,
+			      void (*done)(struct scsi_cmnd *),
+			      ata_xlat_func_t xlat_func);
+static void ata_scsi_simulate_uli(struct ata_port *ap, struct ata_device *dev,
+			      struct scsi_cmnd *cmd,
+			      void (*done)(struct scsi_cmnd *));
+static unsigned int ata_scsi_rbuf_get_uli(struct scsi_cmnd *cmd, u8 **buf_out);
+static inline void ata_scsi_rbuf_put_uli(struct scsi_cmnd *cmd);
+static int atapi_qc_complete_uli(struct ata_queued_cmd *qc, u8 drv_stat);
+static unsigned int atapi_xlat_uli(struct ata_queued_cmd *qc, u8 *scsicmd);
+static int ata_scsi_queuecmd_uli(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *));
+
+static void ata_qc_timeout_uli(struct ata_queued_cmd *qc);
+static void ata_eng_timeout_uli(struct ata_port *ap);
+
+/////////////////////
+struct ata_scsi_args {
+        struct ata_port         *ap;
+        struct ata_device       *dev;
+        struct scsi_cmnd                *cmd;
+        void                    (*done)(struct scsi_cmnd *);
+};
+/* libata-core.c */
+extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap, struct ata_device *dev);
+extern int ata_qc_issue(struct ata_queued_cmd *qc);
+
+/* libata-scsi.c */
+extern void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat);
+
+extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen);
+extern unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen);
+extern unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen);
+extern unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen);
+extern unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen);
+extern unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen);
+extern unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen);
+extern unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen);
+extern void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 asc, u8 ascq);
+extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args, unsigned int (*actor) (struct ata_scsi_args *args,
+                                           u8 *rbuf, unsigned int buflen));
+                                           
+static inline void ata_bad_scsiop(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *));
+static inline void ata_bad_cdb(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *));
+static inline void ata_bad_scsiop(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+{
+        ata_scsi_badcmd(cmd, done, 0x20, 0x00);
+}
+
+static inline void ata_bad_cdb(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+{
+        ata_scsi_badcmd(cmd, done, 0x24, 0x00);
+}
+
+static struct pci_device_id uli_pci_tbl[] = {
+	{ PCI_VENDOR_ID_AL, 0x5289, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5289 },
+	{ PCI_VENDOR_ID_AL, 0x5287, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5287 },
+	{ PCI_VENDOR_ID_AL, 0x5281, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5281 },
+	{ }	/* terminate list */
+};
+
+
+static struct pci_driver uli_pci_driver = {
+	.name			= DRV_NAME,
+	.id_table		= uli_pci_tbl,
+	.probe			= uli_init_one,
+	.remove			= ata_pci_remove_one,
+};
+
+static Scsi_Host_Template uli_sht = {
+	.module			= THIS_MODULE,
+	.name			= DRV_NAME,
+	.ioctl			= ata_scsi_ioctl,
+	.queuecommand		= ata_scsi_queuecmd_uli,
+	.eh_strategy_handler	= ata_scsi_error,
+	.can_queue		= ATA_DEF_QUEUE,
+	.this_id		= ATA_SHT_THIS_ID,
+	.sg_tablesize		= ATA_MAX_PRD,
+	.max_sectors		= ATA_MAX_SECTORS,
+	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
+	.emulated		= ATA_SHT_EMULATED,
+	.use_clustering		= ATA_SHT_USE_CLUSTERING,
+	.proc_name		= DRV_NAME,
+	.dma_boundary		= ATA_DMA_BOUNDARY,
+	.slave_configure	= ata_scsi_slave_config,
+	.bios_param		= ata_std_bios_param,
+};
+
+static struct ata_port_operations uli_ops = {
+	.port_disable		= ata_port_disable,
+	.tf_load		= ata_tf_load,
+	.tf_read		= ata_tf_read,
+	.check_status		= ata_check_status,
+	.exec_command		= ata_exec_command,
+	.dev_select		= ata_std_dev_select,
+	.phy_reset		= sata_phy_reset,
+	.bmdma_setup            = ata_bmdma_setup,
+	.bmdma_start            = ata_bmdma_start,
+	.qc_prep		= ata_qc_prep,
+	.qc_issue		= ata_qc_issue_prot,
+	.eng_timeout		= ata_eng_timeout_uli,
+	.irq_handler		= ata_interrupt,
+	.irq_clear		= ata_bmdma_irq_clear,
+	.scr_read		= uli_scr_read,
+	.scr_write		= uli_scr_write,
+	.port_start		= ata_port_start,
+	.port_stop		= ata_port_stop,
+};
+
+static struct ata_port_info uli_port_info = {
+	.sht		= &uli_sht,
+	.host_flags	= ATA_FLAG_SATA | ATA_FLAG_SATA_RESET |
+			  ATA_FLAG_NO_LEGACY,
+	.pio_mask	= 0x1f,
+	.mwdma_mask	= 0x7,
+	.udma_mask	= 0x7f,
+	.port_ops	= &uli_ops,
+};
+
+MODULE_AUTHOR("Peer Chen");
+MODULE_DESCRIPTION("low-level driver for ULi Electronics SATA controller");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, uli_pci_tbl);
+
+static unsigned int get_scr_cfg_addr(struct ata_port *ap, unsigned int sc_reg)
+{
+	return ap->ioaddr.scr_addr + (4 * sc_reg);
+}
+
+static u32 uli_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
+{
+	unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg);
+	u32 val;
+
+	pci_read_config_dword(ap->host_set->pdev, cfg_addr, &val);
+	return val;
+}
+
+static void uli_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
+{
+	unsigned int cfg_addr = get_scr_cfg_addr(ap, scr);
+
+	pci_write_config_dword(ap->host_set->pdev, cfg_addr, val);
+}
+
+static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg)
+{
+	if (sc_reg > SCR_CONTROL)
+		return 0xffffffffU;
+
+	return uli_scr_cfg_read(ap, sc_reg);
+}
+
+static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+{
+	if (sc_reg > SCR_CONTROL)	//SCR_CONTROL=2, SCR_ERROR=1, SCR_STATUS=0
+		return;
+
+	uli_scr_cfg_write(ap, sc_reg, val);
+}
+
+/* move to PCI layer, integrate w/ MSI stuff */
+static void pci_enable_intx(struct pci_dev *pdev)
+{
+	u16 pci_command;
+
+	pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
+	if (pci_command & PCI_COMMAND_INTX_DISABLE) {
+		pci_command &= ~PCI_COMMAND_INTX_DISABLE;
+		pci_write_config_word(pdev, PCI_COMMAND, pci_command);
+	}
+}
+
+static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	struct ata_probe_ent *probe_ent = NULL;
+	int rc;
+	unsigned int board_idx = (unsigned int) ent->driver_data;
+	struct ata_port_info *ppi;
+		
+	rc = pci_enable_device(pdev);
+	if (rc)
+		return rc;
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc)
+		goto err_out;
+
+	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+
+	ppi = &uli_port_info;
+	probe_ent = ata_pci_init_native_mode(pdev, &ppi);
+	
+	if (!probe_ent) {
+		rc = -ENOMEM;
+		goto err_out_regions;
+	}
+
+	switch (board_idx) {
+	case uli_5287:
+		probe_ent->port[0].scr_addr = ULI5287_BASE;
+		probe_ent->port[1].scr_addr = ULI5287_BASE + ULI5287_OFFS;
+        	probe_ent->n_ports = 4;
+ 
+        	probe_ent->port[2].cmd_addr = pci_resource_start(pdev, 0) + 8;
+		probe_ent->port[2].altstatus_addr =
+ 		probe_ent->port[2].ctl_addr =
+ 				 (pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS) + 4;
+ 		probe_ent->port[2].bmdma_addr = pci_resource_start(pdev, 4) + 16;
+ 		probe_ent->port[2].scr_addr = ULI5287_BASE + ULI5287_OFFS*4;
+
+ 		probe_ent->port[3].cmd_addr = pci_resource_start(pdev, 2) + 8;
+ 		probe_ent->port[3].altstatus_addr =
+ 		probe_ent->port[3].ctl_addr =
+ 				 (pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS) + 4;
+ 		probe_ent->port[3].bmdma_addr = pci_resource_start(pdev, 4) + 24;
+ 		probe_ent->port[3].scr_addr = ULI5287_BASE + ULI5287_OFFS*5;
+
+ 		ata_std_ports(&probe_ent->port[2]);
+ 		ata_std_ports(&probe_ent->port[3]);
+ 		break;
+		
+	case uli_5289:
+       	probe_ent->port[0].scr_addr = ULI5287_BASE;
+		probe_ent->port[1].scr_addr = ULI5287_BASE + ULI5287_OFFS;
+		break;
+
+	case uli_5281:
+	 	probe_ent->port[0].scr_addr = ULI5281_BASE;
+ 		probe_ent->port[1].scr_addr = ULI5281_BASE + ULI5281_OFFS;
+ 		break;
+		
+	default:
+		BUG();
+		break;
+	}
+	pci_set_master(pdev);
+	pci_enable_intx(pdev);
+
+	/* FIXME: check ata_device_add return value */
+	ata_device_add(probe_ent);
+	kfree(probe_ent);
+
+	return 0;
+
+err_out_regions:
+	pci_release_regions(pdev);
+
+err_out:
+	pci_disable_device(pdev);
+	return rc;
+
+}
+
+static int __init uli_init(void)
+{
+	return pci_module_init(&uli_pci_driver);
+}
+
+static void __exit uli_exit(void)
+{
+	pci_unregister_driver(&uli_pci_driver);
+}
+
+//add by clear zhang 2004/12/13
+
+/**
+ *	ata_scsi_find_dev_uli - lookup ata_device from scsi_cmnd
+ *	@ap: ATA port to which the device is attached
+ *	@cmd: SCSI command to be sent to the device
+ *
+ *	Given various information provided in struct scsi_cmnd,
+ *	map that onto an ATA bus, and using that mapping
+ *	determine which ata_device is associated with the
+ *	SCSI command to be sent.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	Associated ATA device, or %NULL if not found.
+ */
+
+static struct ata_device *
+ata_scsi_find_dev_uli(struct ata_port *ap, struct scsi_device *scsidev)
+{
+	struct ata_device *dev;
+
+	/* skip commands not addressed to targets we simulate */
+	if (likely(scsidev->id < ATA_MAX_DEVICES))
+		dev = &ap->device[scsidev->id];
+	else
+		return NULL;
+
+	if (unlikely((scsidev->channel != 0) ||
+		     (scsidev->lun != 0)))
+		return NULL;
+
+	if (unlikely(!ata_dev_present(dev)))
+		return NULL;
+
+#ifndef ATA_ENABLE_ATAPI
+	if (unlikely(dev->class == ATA_DEV_ATAPI))
+		return NULL;
+#endif
+
+	return dev;
+}
+
+//////////////////////////////////////////////////////////////////
+/**
+ *	ata_scsi_flush_xlat_uli - Translate SCSI SYNCHRONIZE CACHE command
+ *	@qc: Storage for translated ATA taskfile
+ *	@scsicmd: SCSI command to translate (ignored)
+ *
+ *	Sets up an ATA taskfile to issue FLUSH CACHE or
+ *	FLUSH CACHE EXT.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	Zero on success, non-zero on error.
+ */
+
+static unsigned int ata_scsi_flush_xlat_uli(struct ata_queued_cmd *qc, u8 *scsicmd)
+{
+	struct ata_taskfile *tf = &qc->tf;
+
+	tf->flags |= ATA_TFLAG_DEVICE;
+	tf->protocol = ATA_PROT_NODATA;
+
+	if ((tf->flags & ATA_TFLAG_LBA48) &&
+	    (ata_id_has_flush_ext(qc->dev)))
+		tf->command = ATA_CMD_FLUSH_EXT;
+	else
+		tf->command = ATA_CMD_FLUSH;
+
+	return 0;
+}
+
+/**
+ *	ata_scsi_verify_xlat_uli - Translate SCSI VERIFY command into an ATA one
+ *	@qc: Storage for translated ATA taskfile
+ *	@scsicmd: SCSI command to translate
+ *
+ *	Converts SCSI VERIFY command to an ATA READ VERIFY command.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	Zero on success, non-zero on error.
+ */
+
+static unsigned int ata_scsi_verify_xlat_uli(struct ata_queued_cmd *qc, u8 *scsicmd)
+{
+	struct ata_taskfile *tf = &qc->tf;
+	unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48;
+	u64 dev_sectors = qc->dev->n_sectors;
+	u64 sect = 0;
+	u32 n_sect = 0;
+
+	tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+	tf->protocol = ATA_PROT_NODATA;
+	tf->device |= ATA_LBA;
+
+	if (scsicmd[0] == VERIFY) {
+		sect |= ((u64)scsicmd[2]) << 24;
+		sect |= ((u64)scsicmd[3]) << 16;
+		sect |= ((u64)scsicmd[4]) << 8;
+		sect |= ((u64)scsicmd[5]);
+
+		n_sect |= ((u32)scsicmd[7]) << 8;
+		n_sect |= ((u32)scsicmd[8]);
+	}
+
+	else if (scsicmd[0] == VERIFY_16) {
+		sect |= ((u64)scsicmd[2]) << 56;
+		sect |= ((u64)scsicmd[3]) << 48;
+		sect |= ((u64)scsicmd[4]) << 40;
+		sect |= ((u64)scsicmd[5]) << 32;
+		sect |= ((u64)scsicmd[6]) << 24;
+		sect |= ((u64)scsicmd[7]) << 16;
+		sect |= ((u64)scsicmd[8]) << 8;
+		sect |= ((u64)scsicmd[9]);
+
+		n_sect |= ((u32)scsicmd[10]) << 24;
+		n_sect |= ((u32)scsicmd[11]) << 16;
+		n_sect |= ((u32)scsicmd[12]) << 8;
+		n_sect |= ((u32)scsicmd[13]);
+	}
+
+	else
+		return 1;
+
+	if (!n_sect)
+		return 1;
+	if (sect >= dev_sectors)
+		return 1;
+	if ((sect + n_sect) > dev_sectors)
+		return 1;
+	if (lba48) {
+		if (n_sect > (64 * 1024))
+			return 1;
+	} else {
+		if (n_sect > 256)
+			return 1;
+	}
+
+	if (lba48) {
+		tf->hob_nsect = (n_sect >> 8) & 0xff;
+
+		tf->hob_lbah = (sect >> 40) & 0xff;
+		tf->hob_lbam = (sect >> 32) & 0xff;
+		tf->hob_lbal = (sect >> 24) & 0xff;
+	} else
+		tf->device |= (sect >> 24) & 0xf;
+
+	tf->nsect = n_sect & 0xff;
+
+	tf->hob_lbah = (sect >> 16) & 0xff;
+	tf->hob_lbam = (sect >> 8) & 0xff;
+	tf->hob_lbal = sect & 0xff;
+
+	return 0;
+}
+
+/**
+ *	ata_scsi_rw_xlat_uli - Translate SCSI r/w command into an ATA one
+ *	@qc: Storage for translated ATA taskfile
+ *	@scsicmd: SCSI command to translate
+ *
+ *	Converts any of six SCSI read/write commands into the
+ *	ATA counterpart, including starting sector (LBA),
+ *	sector count, and taking into account the device's LBA48
+ *	support.
+ *
+ *	Commands %READ_6, %READ_10, %READ_16, %WRITE_6, %WRITE_10, and
+ *	%WRITE_16 are currently supported.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	Zero on success, non-zero on error.
+ */
+
+static unsigned int ata_scsi_rw_xlat_uli(struct ata_queued_cmd *qc, u8 *scsicmd)
+{
+	struct ata_taskfile *tf = &qc->tf;
+	unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48;
+
+	tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+	tf->protocol = qc->dev->xfer_protocol;
+	tf->device |= ATA_LBA;
+
+	if (scsicmd[0] == READ_10 || scsicmd[0] == READ_6 ||
+	    scsicmd[0] == READ_16) {
+		tf->command = qc->dev->read_cmd;
+	} else {
+		tf->command = qc->dev->write_cmd;
+		tf->flags |= ATA_TFLAG_WRITE;
+	}
+
+	if (scsicmd[0] == READ_10 || scsicmd[0] == WRITE_10) {
+		if (lba48) {
+			tf->hob_nsect = scsicmd[7];
+			tf->hob_lbal = scsicmd[2];
+
+			qc->nsect = ((unsigned int)scsicmd[7] << 8) |
+					scsicmd[8];
+		} else {
+			/* if we don't support LBA48 addressing, the request
+			 * -may- be too large. */
+			if ((scsicmd[2] & 0xf0) || scsicmd[7])
+				return 1;
+
+			/* stores LBA27:24 in lower 4 bits of device reg */
+			tf->device |= scsicmd[2];
+
+			qc->nsect = scsicmd[8];
+		}
+
+		tf->nsect = scsicmd[8];
+		tf->lbal = scsicmd[5];
+		tf->lbam = scsicmd[4];
+		tf->lbah = scsicmd[3];
+
+		VPRINTK("ten-byte command\n");
+		return 0;
+	}
+
+	if (scsicmd[0] == READ_6 || scsicmd[0] == WRITE_6) {
+		qc->nsect = tf->nsect = scsicmd[4];
+		tf->lbal = scsicmd[3];
+		tf->lbam = scsicmd[2];
+		tf->lbah = scsicmd[1] & 0x1f; /* mask out reserved bits */
+
+		VPRINTK("six-byte command\n");
+		return 0;
+	}
+
+	if (scsicmd[0] == READ_16 || scsicmd[0] == WRITE_16) {
+		/* rule out impossible LBAs and sector counts */
+		if (scsicmd[2] || scsicmd[3] || scsicmd[10] || scsicmd[11])
+			return 1;
+
+		if (lba48) {
+			tf->hob_nsect = scsicmd[12];
+			tf->hob_lbal = scsicmd[6];
+			tf->hob_lbam = scsicmd[5];
+			tf->hob_lbah = scsicmd[4];
+
+			qc->nsect = ((unsigned int)scsicmd[12] << 8) |
+					scsicmd[13];
+		} else {
+			/* once again, filter out impossible non-zero values */
+			if (scsicmd[4] || scsicmd[5] || scsicmd[12] ||
+			    (scsicmd[6] & 0xf0))
+				return 1;
+
+			/* stores LBA27:24 in lower 4 bits of device reg */
+			tf->device |= scsicmd[2];
+
+			qc->nsect = scsicmd[13];
+		}
+
+		tf->nsect = scsicmd[13];
+		tf->lbal = scsicmd[9];
+		tf->lbam = scsicmd[8];
+		tf->lbah = scsicmd[7];
+
+		VPRINTK("sixteen-byte command\n");
+		return 0;
+	}
+
+	DPRINTK("no-byte command\n");
+	return 1;
+}
+
+/**
+ *	ata_get_xlat_func_uli - check if SCSI to ATA translation is possible
+ *	@dev: ATA device
+ *	@cmd: SCSI command opcode to consider
+ *
+ *	Look up the SCSI command given, and determine whether the
+ *	SCSI command is to be translated or simulated.
+ *
+ *	RETURNS:
+ *	Pointer to translation function if possible, %NULL if not.
+ */
+
+static inline ata_xlat_func_t ata_get_xlat_func_uli(struct ata_device *dev, u8 cmd)
+{
+	switch (cmd) {
+	case READ_6:
+	case READ_10:
+	case READ_16:
+
+	case WRITE_6:
+	case WRITE_10:
+	case WRITE_16:
+		return ata_scsi_rw_xlat_uli;
+
+	case SYNCHRONIZE_CACHE:
+		if (ata_try_flush_cache(dev))
+			return ata_scsi_flush_xlat_uli;
+		break;
+
+	case VERIFY:
+	case VERIFY_16:
+		return ata_scsi_verify_xlat_uli;
+	}
+
+	return NULL;
+}
+///////////////////////////////////////////////////////////////
+
+/**
+ *	ata_scsi_qc_new_uli - acquire new ata_queued_cmd reference
+ *	@ap: ATA port to which the new command is attached
+ *	@dev: ATA device to which the new command is attached
+ *	@cmd: SCSI command that originated this ATA command
+ *	@done: SCSI command completion function
+ *
+ *	Obtain a reference to an unused ata_queued_cmd structure,
+ *	which is the basic libata structure representing a single
+ *	ATA command sent to the hardware.
+ *
+ *	If a command was available, fill in the SCSI-specific
+ *	portions of the structure with information on the
+ *	current command.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	Command allocated, or %NULL if none available.
+ */
+struct ata_queued_cmd *ata_scsi_qc_new_uli(struct ata_port *ap,
+				       struct ata_device *dev,
+				       struct scsi_cmnd *cmd,
+				       void (*done)(struct scsi_cmnd *))
+{
+	struct ata_queued_cmd *qc;
+
+	qc = ata_qc_new_init(ap, dev);
+	if (qc) {
+		qc->scsicmd = cmd;
+		qc->scsidone = done;
+
+		if (cmd->use_sg) {
+			qc->sg = (struct scatterlist *) cmd->request_buffer;
+			qc->n_elem = cmd->use_sg;
+		} else {
+			qc->sg = &qc->sgent;
+			qc->n_elem = 1;
+		}
+	} else {
+		cmd->result = (DID_OK << 16) | (QUEUE_FULL << 1);
+		done(cmd);
+	}
+
+	return qc;
+}
+/////////////////////////////////////////////////////////////////////
+
+static int ata_scsi_qc_complete_uli(struct ata_queued_cmd *qc, u8 drv_stat)
+{
+	struct scsi_cmnd *cmd = qc->scsicmd;
+	
+	// add by clear cheung 2004/12/7 for ULi M5281 workaroud	
+	if(qc->ap->host_set->pdev->vendor==0x10b9 &&
+		qc->ap->host_set->pdev->device==0x5281)
+	{
+		
+		struct pci_dev *pdev_m5281=qc->ap->host_set->pdev;
+		u8 m5281_revision;
+		
+		cmd->result = SAM_STAT_GOOD;
+			              
+		pci_read_config_byte(pdev_m5281, PCI_REVISION_ID, &m5281_revision);
+		//printk("m5281_revision=0x%x\n",m5281_revision);
+		//version 0xa0,0xa1,0xb1 need workaroud	
+		if(m5281_revision==0xa0 ||m5281_revision==0xa1 ||m5281_revision==0xb1 )
+		{
+			u16 error_m5281;
+			unsigned long	scr_addr_m5281 = qc->ap->ioaddr.scr_addr;
+			
+			pci_read_config_word(pdev_m5281,scr_addr_m5281+6, &error_m5281);
+			
+			if ( unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ)) && iftimeout==0/*express not timeout*/)
+				ata_to_sense_error(qc, drv_stat);
+			//time out or drive status is ok			
+			else if ((error_m5281 & 0x3f8)!=0 || iftimeout==1) //the src errore present
+			{
+				u32 scr4_m5281;
+				u8  reset_m5281, stus, scr0_m5281;
+				
+				u8 kk, jj;
+              			u8 comreset=1, softreset=1;//success=0, fail=1
+		
+				printk("ULi sata error:0x%x\n",error_m5281);
+				//reset
+				// dma have been closed
+				//__save_flags(flags_m5281);
+				//__cli();
+				//com reset
+				for(kk=0;kk<20;kk++)
+				{
+					pci_read_config_byte(pdev_m5281,scr_addr_m5281+8,&reset_m5281);
+					reset_m5281 = reset_m5281 & 0xfe;
+					pci_write_config_byte(pdev_m5281,scr_addr_m5281+8,reset_m5281);
+					reset_m5281 = reset_m5281 | 0x01;
+					pci_write_config_byte(pdev_m5281,scr_addr_m5281+8,reset_m5281);		
+					
+					//delay two ms
+					mdelay(2);
+					
+					//reallert and clear erro bit
+					reset_m5281 = reset_m5281 & 0xfe;
+		        		pci_write_config_byte(pdev_m5281,scr_addr_m5281+8,reset_m5281);
+					mdelay(2);
+										
+					pci_read_config_byte(pdev_m5281,scr_addr_m5281,&scr0_m5281);
+					pci_read_config_dword(pdev_m5281,scr_addr_m5281+4,&scr4_m5281);
+					if(scr0_m5281!=0x13 ||(scr4_m5281 & 0x50000)!= 0x00050000 )
+					{
+						print_clear(("phy reset failed\n"));
+						print_clear(("scr0=0x%x\n", scr0_m5281));
+						print_clear(("scr4=0x%x\n", scr4_m5281));
+						continue;
+					}
+					else
+					{
+						//print_clear(("com reset success\n"));
+						//clear error bits
+						pci_write_config_dword(pdev_m5281,scr_addr_m5281+4,scr4_m5281);
+
+						comreset=0;//success
+						break;
+					}
+					
+				}
+				
+				if(comreset==0)
+				{
+					//stus= inb(qc->ap->ioaddr.status_addr);// get drive status 
+					jj=0;
+					do
+					{
+						mdelay(2);
+						stus= inb(qc->ap->ioaddr.status_addr);// get drive status 
+						jj++;
+						if(jj>=150)
+						{
+							break;
+						}
+					}while (stus!=0x50);
+					
+					//print_clear(("jj=0x%x\n", jj));
+										
+					if(stus!=0x50 /*&& iftimeout==1*/)
+					{
+						//print_clear(("soft reset\n"));
+						for(kk=0;kk<5;kk++)
+						{
+							outb(0x04,qc->ap->ioaddr.ctl_addr);	// set SRST 
+							mdelay(5);			// more than enough time 
+							outb(0,qc->ap->ioaddr.ctl_addr);	// clear 
+							jj=0;
+							do
+							{
+								mdelay(1);
+								stus= inb(qc->ap->ioaddr.status_addr);// get drive status 
+								jj++;
+								if(jj>=100)
+								{
+									break;
+								}
+							}while (stus!=0x50);
+
+							if(stus==0x50)
+							{
+								softreset=0;//sucess
+								break;
+							}
+							
+						}						
+				
+					}
+					if(stus==0x50)
+					{
+						softreset=0;
+					}
+					print_clear(("ULi drive status=0x%x\n",stus));
+					
+				}
+				iftimeout=0;			
+				//__restore_flags(flags_m5281);
+				
+
+				//set the command
+				//trnslate error can be done accoring to ata_to_sense_error
+						
+				if(comreset==1)
+				{
+					ata_to_sense_error(qc, 0x20);
+				}
+				else 
+				{
+					//print_clear(("to sys\n"));
+					ata_to_sense_error(qc, 0x1);	
+				}
+			}
+			else
+			{
+				cmd->result = SAM_STAT_GOOD;
+			}
+
+		}
+		else
+		{
+			if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ)))
+				ata_to_sense_error(qc, drv_stat);
+			else
+				cmd->result = SAM_STAT_GOOD;
+		}
+	}
+	//end add by clear cheung 2004/12/7
+	else
+	{
+
+		if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ)))
+			ata_to_sense_error(qc, drv_stat);
+		else
+			cmd->result = SAM_STAT_GOOD;
+	}
+
+	qc->scsidone(cmd);
+
+	return 0;
+}
+
+/**
+ *	ata_scsi_translate_uli - Translate then issue SCSI command to ATA device
+ *	@ap: ATA port to which the command is addressed
+ *	@dev: ATA device to which the command is addressed
+ *	@cmd: SCSI command to execute
+ *	@done: SCSI command completion function
+ *	@xlat_func: Actor which translates @cmd to an ATA taskfile
+ *
+ *	Our ->queuecommand() function has decided that the SCSI
+ *	command issued can be directly translated into an ATA
+ *	command, rather than handled internally.
+ *
+ *	This function sets up an ata_queued_cmd structure for the
+ *	SCSI command, and sends that ata_queued_cmd to the hardware.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+static void ata_scsi_translate_uli(struct ata_port *ap, struct ata_device *dev,
+			      struct scsi_cmnd *cmd,
+			      void (*done)(struct scsi_cmnd *),
+			      ata_xlat_func_t xlat_func)
+{
+	struct ata_queued_cmd *qc;
+	u8 *scsicmd = cmd->cmnd;
+
+	VPRINTK("ENTER\n");
+
+	qc = ata_scsi_qc_new_uli(ap, dev, cmd, done);
+	if (!qc)
+		return;
+
+	/* data is present; dma-map it */
+	if (cmd->sc_data_direction == SCSI_DATA_READ ||
+	    cmd->sc_data_direction == SCSI_DATA_WRITE) {
+		if (unlikely(cmd->request_bufflen < 1)) {
+			printk(KERN_WARNING "ata%u(%u): WARNING: zero len r/w req\n",
+			       ap->id, dev->devno);
+			goto err_out;
+		}
+
+		if (cmd->use_sg)
+			ata_sg_init(qc, cmd->request_buffer, cmd->use_sg);
+		else
+			ata_sg_init_one(qc, cmd->request_buffer,
+					cmd->request_bufflen);
+
+		qc->pci_dma_dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+	}
+
+	qc->complete_fn = ata_scsi_qc_complete_uli;
+
+	if (xlat_func(qc, scsicmd))
+		goto err_out;
+
+	/* select device, send command to hardware */
+	if (ata_qc_issue(qc))
+		goto err_out;
+
+	VPRINTK("EXIT\n");
+	return;
+
+err_out:
+	ata_bad_cdb(cmd, done);
+	DPRINTK("EXIT - badcmd\n");
+}
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ *	ata_scsi_simulate_uli - simulate SCSI command on ATA device
+ *	@ap: Port to which ATA device is attached.
+ *	@dev: Target device for CDB.
+ *	@cmd: SCSI command being sent to device.
+ *	@done: SCSI command completion function.
+ *
+ *	Interprets and directly executes a select list of SCSI commands
+ *	that can be handled internally.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+static void ata_scsi_simulate_uli(struct ata_port *ap, struct ata_device *dev,
+			      struct scsi_cmnd *cmd,
+			      void (*done)(struct scsi_cmnd *))
+{
+	struct ata_scsi_args args;
+	u8 *scsicmd = cmd->cmnd;
+
+	args.ap = ap;
+	args.dev = dev;
+	args.cmd = cmd;
+	args.done = done;
+
+	switch(scsicmd[0]) {
+		/* no-op's, complete with success */
+		case SYNCHRONIZE_CACHE:
+		case REZERO_UNIT:
+		case SEEK_6:
+		case SEEK_10:
+		case TEST_UNIT_READY:
+		case FORMAT_UNIT:		/* FIXME: correct? */
+		case SEND_DIAGNOSTIC:		/* FIXME: correct? */
+			ata_scsi_rbuf_fill(&args, ata_scsiop_noop);
+			break;
+
+		case INQUIRY:
+			if (scsicmd[1] & 2)	           /* is CmdDt set?  */
+				ata_bad_cdb(cmd, done);
+			else if ((scsicmd[1] & 1) == 0)    /* is EVPD clear? */
+				ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std);
+			else if (scsicmd[2] == 0x00)
+				ata_scsi_rbuf_fill(&args, ata_scsiop_inq_00);
+			else if (scsicmd[2] == 0x80)
+				ata_scsi_rbuf_fill(&args, ata_scsiop_inq_80);
+			else if (scsicmd[2] == 0x83)
+				ata_scsi_rbuf_fill(&args, ata_scsiop_inq_83);
+			else
+				ata_bad_cdb(cmd, done);
+			break;
+
+		case MODE_SENSE:
+		case MODE_SENSE_10:
+			ata_scsi_rbuf_fill(&args, ata_scsiop_mode_sense);
+			break;
+
+		case MODE_SELECT:	/* unconditionally return */
+		case MODE_SELECT_10:	/* bad-field-in-cdb */
+			ata_bad_cdb(cmd, done);
+			break;
+
+		case READ_CAPACITY:
+			ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
+			break;
+
+		case SERVICE_ACTION_IN:
+			if ((scsicmd[1] & 0x1f) == SAI_READ_CAPACITY_16)
+				ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
+			else
+				ata_bad_cdb(cmd, done);
+			break;
+
+		case REPORT_LUNS:
+			ata_scsi_rbuf_fill(&args, ata_scsiop_report_luns);
+			break;
+
+		/* mandantory commands we haven't implemented yet */
+		case REQUEST_SENSE:
+
+		/* all other commands */
+		default:
+			ata_bad_scsiop(cmd, done);
+			break;
+	}
+}
+//////////////////////////////////////////////////////////////////////
+
+/**
+ *	ata_scsi_rbuf_get_uli - Map response buffer.
+ *	@cmd: SCSI command containing buffer to be mapped.
+ *	@buf_out: Pointer to mapped area.
+ *
+ *	Maps buffer contained within SCSI command @cmd.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	Length of response buffer.
+ */
+
+static unsigned int ata_scsi_rbuf_get_uli(struct scsi_cmnd *cmd, u8 **buf_out)
+{
+	u8 *buf;
+	unsigned int buflen;
+
+	if (cmd->use_sg) {
+		struct scatterlist *sg;
+
+		sg = (struct scatterlist *) cmd->request_buffer;
+		buf = kmap_atomic(sg->page, KM_USER0) + sg->offset;
+		buflen = sg->length;
+	} else {
+		buf = cmd->request_buffer;
+		buflen = cmd->request_bufflen;
+	}
+
+	memset(buf, 0, buflen);
+	*buf_out = buf;
+	return buflen;
+}
+
+/**
+ *	ata_scsi_rbuf_put_uli - Unmap response buffer.
+ *	@cmd: SCSI command containing buffer to be unmapped.
+ *
+ *	Unmaps response buffer contained within @cmd.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+static inline void ata_scsi_rbuf_put_uli(struct scsi_cmnd *cmd)
+{
+	if (cmd->use_sg) {
+		struct scatterlist *sg;
+
+		sg = (struct scatterlist *) cmd->request_buffer;
+		kunmap_atomic(sg->page, KM_USER0);
+	}
+}
+static int atapi_qc_complete_uli(struct ata_queued_cmd *qc, u8 drv_stat)
+{
+	struct scsi_cmnd *cmd = qc->scsicmd;
+	
+	// add by clear cheung 2004/12/7 for ULi M5281 workaroud	
+	if(qc->ap->host_set->pdev->vendor==0x10b9 &&
+		qc->ap->host_set->pdev->device==0x5281)
+	{
+		
+		struct pci_dev *pdev_m5281=qc->ap->host_set->pdev;
+		u8 m5281_revision;
+		
+		cmd->result = SAM_STAT_GOOD;
+			              
+		pci_read_config_byte(pdev_m5281, PCI_REVISION_ID, &m5281_revision);
+		//printk("m5281_revision=0x%x\n",m5281_revision);
+		//version 0xa0,0xa1,0xb1 need workaroud	
+		if(m5281_revision==0xa0 ||m5281_revision==0xa1 ||m5281_revision==0xb1 )
+		{
+			u16 error_m5281;
+			unsigned long	scr_addr_m5281 = qc->ap->ioaddr.scr_addr;
+			
+			pci_read_config_word(pdev_m5281,scr_addr_m5281+6, &error_m5281);
+			
+			if ( unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ)) && iftimeout==0/*express not timeout*/)
+				cmd->result = SAM_STAT_CHECK_CONDITION;
+			//time out or drive status is ok			
+			else if ((error_m5281 & 0x3f8)!=0 || iftimeout==1) //the src errore present
+			{
+				u32 scr4_m5281;
+				u8  reset_m5281, stus, scr0_m5281;
+				
+				u8 kk, jj;
+              			u8 comreset=1, softreset=1;//success=0, fail=1
+		
+				printk("ULi sata error:0x%x\n",error_m5281);
+				//reset
+				// dma have been closed
+				//__save_flags(flags_m5281);
+				//__cli();
+				//com reset
+				for(kk=0;kk<20;kk++)
+				{
+					pci_read_config_byte(pdev_m5281,scr_addr_m5281+8,&reset_m5281);
+					reset_m5281 = reset_m5281 & 0xfe;
+					pci_write_config_byte(pdev_m5281,scr_addr_m5281+8,reset_m5281);
+					reset_m5281 = reset_m5281 | 0x01;
+					pci_write_config_byte(pdev_m5281,scr_addr_m5281+8,reset_m5281);		
+					
+					//delay two ms
+					mdelay(2);
+					
+					//reallert and clear erro bit
+					reset_m5281 = reset_m5281 & 0xfe;
+		        		pci_write_config_byte(pdev_m5281,scr_addr_m5281+8,reset_m5281);
+					mdelay(2);
+										
+					pci_read_config_byte(pdev_m5281,scr_addr_m5281,&scr0_m5281);
+					pci_read_config_dword(pdev_m5281,scr_addr_m5281+4,&scr4_m5281);
+					if(scr0_m5281!=0x13 ||(scr4_m5281 & 0x50000)!= 0x00050000 )
+					{
+						print_clear(("phy reset failed\n"));
+						print_clear(("scr0=0x%x\n", scr0_m5281));
+						print_clear(("scr4=0x%x\n", scr4_m5281));
+						continue;
+					}
+					else
+					{
+						//print_clear(("com reset success\n"));
+						//clear error bits
+						pci_write_config_dword(pdev_m5281,scr_addr_m5281+4,scr4_m5281);
+
+						comreset=0;//success
+						break;
+					}
+					
+				}
+				
+				if(comreset==0)
+				{
+					//stus= inb(qc->ap->ioaddr.status_addr);// get drive status 
+					jj=0;
+					do
+					{
+						mdelay(2);
+						stus= inb(qc->ap->ioaddr.status_addr);// get drive status 
+						jj++;
+						if(jj>=150)
+						{
+							break;
+						}
+					}while (stus!=0x50);
+					
+					//print_clear(("jj=0x%x\n", jj));
+										
+					if(stus!=0x50 /*&& iftimeout==1*/)
+					{
+						//print_clear(("soft reset\n"));
+						for(kk=0;kk<5;kk++)
+						{
+							outb(0x04,qc->ap->ioaddr.ctl_addr);	// set SRST 
+							mdelay(5);			// more than enough time 
+							outb(0,qc->ap->ioaddr.ctl_addr);	// clear 
+							jj=0;
+							do
+							{
+								mdelay(1);
+								stus= inb(qc->ap->ioaddr.status_addr);// get drive status 
+								jj++;
+								if(jj>=100)
+								{
+									break;
+								}
+							}while (stus!=0x50);
+
+							if(stus==0x50)
+							{
+								softreset=0;//sucess
+								break;
+							}
+							
+						}						
+				
+					}
+					if(stus==0x50)
+					{
+						softreset=0;
+					}
+					print_clear(("ULi drive status=0x%x\n",stus));
+					
+				}
+				iftimeout=0;			
+				//__restore_flags(flags_m5281);
+				
+
+				//set the command
+				//trnslate error can be done accoring to ata_to_sense_error
+				cmd->result = SAM_STAT_CHECK_CONDITION;		
+				/*if(comreset==1)
+				{
+					ata_to_sense_error(qc, 0x20);
+				}
+				else 
+				{
+					//print_clear(("to sys\n"));
+					ata_to_sense_error(qc, 0x1);	
+				}*/
+			}
+			else 
+			{
+				u8 *scsicmd = cmd->cmnd;
+		
+				if (scsicmd[0] == INQUIRY) {
+					u8 *buf = NULL;
+					unsigned int buflen;
+		
+					buflen = ata_scsi_rbuf_get_uli(cmd, &buf);
+					buf[2] = 0x5;
+					buf[3] = (buf[3] & 0xf0) | 2;
+					ata_scsi_rbuf_put_uli(cmd);
+				}
+				cmd->result = SAM_STAT_GOOD;
+			}
+
+		}
+		else
+		{
+			if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ)))
+				cmd->result = SAM_STAT_CHECK_CONDITION;
+			else {
+				u8 *scsicmd = cmd->cmnd;
+		
+				if (scsicmd[0] == INQUIRY) {
+					u8 *buf = NULL;
+					unsigned int buflen;
+		
+					buflen = ata_scsi_rbuf_get_uli(cmd, &buf);
+					buf[2] = 0x5;
+					buf[3] = (buf[3] & 0xf0) | 2;
+					ata_scsi_rbuf_put_uli(cmd);
+				}
+				cmd->result = SAM_STAT_GOOD;
+			}
+		}
+	}
+	//end add by clear cheung 2004/12/7
+	
+	else
+	{
+
+		if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ)))
+			cmd->result = SAM_STAT_CHECK_CONDITION;
+		else {
+			u8 *scsicmd = cmd->cmnd;
+	
+			if (scsicmd[0] == INQUIRY) {
+				u8 *buf = NULL;
+				unsigned int buflen;
+	
+				buflen = ata_scsi_rbuf_get_uli(cmd, &buf);
+				buf[2] = 0x5;
+				buf[3] = (buf[3] & 0xf0) | 2;
+				ata_scsi_rbuf_put_uli(cmd);
+			}
+			cmd->result = SAM_STAT_GOOD;
+		}
+	}
+
+	qc->scsidone(cmd);
+
+	return 0;
+}
+
+/**
+ *	atapi_xlat_uli - Initialize PACKET taskfile
+ *	@qc: command structure to be initialized
+ *	@scsicmd: SCSI CDB associated with this PACKET command
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	Zero on success, non-zero on failure.
+ */
+
+static unsigned int atapi_xlat_uli(struct ata_queued_cmd *qc, u8 *scsicmd)
+{
+	struct scsi_cmnd *cmd = qc->scsicmd;
+	struct ata_device *dev = qc->dev;
+	int using_pio = (dev->flags & ATA_DFLAG_PIO);
+	int nodata = (cmd->sc_data_direction == SCSI_DATA_NONE);
+
+	memcpy(&qc->cdb, scsicmd, qc->ap->cdb_len);
+
+	qc->complete_fn = atapi_qc_complete_uli;
+
+	qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+	if (cmd->sc_data_direction == SCSI_DATA_WRITE) {
+		qc->tf.flags |= ATA_TFLAG_WRITE;
+		DPRINTK("direction: write\n");
+	}
+
+	qc->tf.command = ATA_CMD_PACKET;
+
+	/* no data, or PIO data xfer */
+	if (using_pio || nodata) {
+		if (nodata)
+			qc->tf.protocol = ATA_PROT_ATAPI_NODATA;
+		else
+			qc->tf.protocol = ATA_PROT_ATAPI;
+		qc->tf.lbam = (8 * 1024) & 0xff;
+		qc->tf.lbah = (8 * 1024) >> 8;
+	}
+
+	/* DMA data xfer */
+	else {
+		qc->tf.protocol = ATA_PROT_ATAPI_DMA;
+		qc->tf.feature |= ATAPI_PKT_DMA;
+
+#ifdef ATAPI_ENABLE_DMADIR
+		/* some SATA bridges need us to indicate data xfer direction */
+		if (cmd->sc_data_direction != SCSI_DATA_WRITE)
+			qc->tf.feature |= ATAPI_DMADIR;
+#endif
+	}
+
+	return 0;
+}
+
+/////////////////////////////////////////////////////////////
+/**
+ *	ata_scsi_queuecmd_uli - Issue SCSI cdb to libata-managed device
+ *	@cmd: SCSI command to be sent
+ *	@done: Completion function, called when command is complete
+ *
+ *	In some cases, this function translates SCSI commands into
+ *	ATA taskfiles, and queues the taskfiles to be sent to
+ *	hardware.  In other cases, this function simulates a
+ *	SCSI device by evaluating and responding to certain
+ *	SCSI commands.  This creates the overall effect of
+ *	ATA and ATAPI devices appearing as SCSI devices.
+ *
+ *	LOCKING:
+ *	Releases scsi-layer-held lock, and obtains host_set lock.
+ *
+ *	RETURNS:
+ *	Zero.
+ */
+
+static int ata_scsi_queuecmd_uli(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+{
+	struct ata_port *ap;
+	struct ata_device *dev;
+	struct scsi_device *scsidev = cmd->device;
+
+	ap = (struct ata_port *) &scsidev->host->hostdata[0];
+
+	//ata_scsi_dump_cdb(ap, cmd);
+
+	dev = ata_scsi_find_dev_uli(ap, scsidev);
+	if (unlikely(!dev)) {
+		cmd->result = (DID_BAD_TARGET << 16);
+		done(cmd);
+		goto out_unlock;
+	}
+
+	if (dev->class == ATA_DEV_ATA) {
+		ata_xlat_func_t xlat_func = ata_get_xlat_func_uli(dev,
+							      cmd->cmnd[0]);
+
+		if (xlat_func)
+			ata_scsi_translate_uli(ap, dev, cmd, done, xlat_func);
+		else
+			ata_scsi_simulate_uli(ap, dev, cmd, done);
+	} else
+		ata_scsi_translate_uli(ap, dev, cmd, done, atapi_xlat_uli);
+
+out_unlock:
+	return 0;
+}
+//////////////////////////////////////////////////////////////////////
+
+/**
+ *	ata_qc_timeout_uli - Handle timeout of queued command
+ *	@qc: Command that timed out
+ *
+ *	Some part of the kernel (currently, only the SCSI layer)
+ *	has noticed that the active command on port @ap has not
+ *	completed after a specified length of time.  Handle this
+ *	condition by disabling DMA (if necessary) and completing
+ *	transactions, with error if necessary.
+ *
+ *	This also handles the case of the "lost interrupt", where
+ *	for some reason (possibly hardware bug, possibly driver bug)
+ *	an interrupt was not delivered to the driver, even though the
+ *	transaction completed successfully.
+ *
+ *	LOCKING:
+ */
+
+static void ata_qc_timeout_uli(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	u8 host_stat = 0, drv_stat;
+
+	DPRINTK("ENTER\n");
+
+	/* hack alert!  We cannot use the supplied completion
+	 * function from inside the ->eh_strategy_handler() thread.
+	 * libata is the only user of ->eh_strategy_handler() in
+	 * any kernel, so the default scsi_done() assumes it is
+	 * not being called from the SCSI EH.
+	 */
+	qc->scsidone = scsi_finish_command;
+
+	switch (qc->tf.protocol) {
+
+	case ATA_PROT_DMA:
+	case ATA_PROT_ATAPI_DMA:
+		host_stat = ata_bmdma_status(ap);
+
+		/* before we do anything else, clear DMA-Start bit */
+		ata_bmdma_stop(ap);
+
+		/* fall through */
+
+	default:
+		ata_altstatus(ap);
+		drv_stat = ata_chk_status(ap);
+
+		/* ack bmdma irq events */
+		ata_bmdma_ack_irq(ap);
+
+		printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x host_stat 0x%x\n",
+		       ap->id, qc->tf.command, drv_stat, host_stat);
+
+		/* complete taskfile transaction */
+		ata_qc_complete(qc, drv_stat);
+		break;
+	}
+
+	DPRINTK("EXIT\n");
+}
+
+/**
+ *	ata_eng_timeout_uli - Handle timeout of queued command
+ *	@ap: Port on which timed-out command is active
+ *
+ *	Some part of the kernel (currently, only the SCSI layer)
+ *	has noticed that the active command on port @ap has not
+ *	completed after a specified length of time.  Handle this
+ *	condition by disabling DMA (if necessary) and completing
+ *	transactions, with error if necessary.
+ *
+ *	This also handles the case of the "lost interrupt", where
+ *	for some reason (possibly hardware bug, possibly driver bug)
+ *	an interrupt was not delivered to the driver, even though the
+ *	transaction completed successfully.
+ *
+ *	LOCKING:
+ *	Inherited from SCSI layer (none, can sleep)
+ */
+
+static void ata_eng_timeout_uli(struct ata_port *ap)
+{
+	struct ata_queued_cmd *qc;
+
+	DPRINTK("ENTER\n");
+	
+	//add by clear cheung 2004/12/7
+	iftimeout=1;
+
+	qc = ata_qc_from_tag(ap, ap->active_tag);
+	if (!qc) {
+		printk(KERN_ERR "ata%u: BUG: timeout without command\n",
+		       ap->id);
+		goto out;
+	}
+
+	ata_qc_timeout_uli(qc);
+
+out:
+	DPRINTK("EXIT\n");
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+module_init(uli_init);
+module_exit(uli_exit);

                 reply	other threads:[~2004-12-14  6:39 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=OF1118CDDC.A4BA64D4-ON48256F6A.0023C04B@uli.com.tw \
    --to=clear.zhang@uli.com.tw \
    --cc=Emily.Jiang@uli.com.tw \
    --cc=Eric.Lo@uli.com.tw \
    --cc=Peer.Chen@uli.com.tw \
    --cc=andrebalsa@mailingaddress.org \
    --cc=jgarzik@pobox.com \
    --cc=linux-ide@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®