* re: Re: [patch] scsi/libata: correct bug for ULi M5281
@ 2004-12-14 6:36 Clear.Zhang
0 siblings, 0 replies; only message in thread
From: Clear.Zhang @ 2004-12-14 6:36 UTC (permalink / raw)
To: Jeff Garzik
Cc: linux-kernel, linux-ide, andrebalsa, Peer.Chen, Emily.Jiang, Eric.Lo
[-- 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);
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2004-12-14 6:39 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-12-14 6:36 Re: [patch] scsi/libata: correct bug for ULi M5281 Clear.Zhang
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®