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-08 13:41:20.306537688 +0800 @@ -47,6 +47,8 @@ #include "libata.h" +u8 iftimeout=0; + static unsigned int ata_busy_sleep (struct ata_port *ap, unsigned long tmout_pat, unsigned long tmout); @@ -2421,6 +2423,9 @@ void ata_eng_timeout(struct ata_port *ap struct ata_queued_cmd *qc; DPRINTK("ENTER\n"); + + //add by clear zhang 2004/12/7 + iftimeout=1; qc = ata_qc_from_tag(ap, ap->active_tag); if (!qc) { diff -uprN linux-2.6.9-vanilla/drivers/scsi/libata-scsi.c linux-2.6.9/drivers/scsi/libata-scsi.c --- linux-2.6.9-vanilla/drivers/scsi/libata-scsi.c 2004-10-19 05:53:51.000000000 +0800 +++ linux-2.6.9/drivers/scsi/libata-scsi.c 2004-12-08 13:42:41.305224016 +0800 @@ -24,6 +24,7 @@ #include #include +#include #include #include #include "scsi.h" @@ -33,6 +34,11 @@ #include "libata.h" +//add by clear zhang 2004/12/7 +#define print_clear(_x_) printk _x_ +//#define print_clear(_x_) NULL +extern u8 iftimeout; + typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc, u8 *scsicmd); static void ata_scsi_simulate(struct ata_port *ap, struct ata_device *dev, struct scsi_cmnd *cmd, @@ -622,11 +628,174 @@ static unsigned int ata_scsi_rw_xlat(str static int ata_scsi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) { struct scsi_cmnd *cmd = qc->scsicmd; + + // add by clear zhang 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; + } - if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) - ata_to_sense_error(qc, drv_stat); + } + 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 zhang 2004/12/7 else - cmd->result = SAM_STAT_GOOD; + { + + 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); @@ -1247,22 +1416,209 @@ void ata_scsi_badcmd(struct scsi_cmnd *c static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) { struct scsi_cmnd *cmd = qc->scsicmd; + + // add by clear zhang 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(cmd, &buf); + buf[2] = 0x5; + buf[3] = (buf[3] & 0xf0) | 2; + ata_scsi_rbuf_put(cmd); + } + cmd->result = SAM_STAT_GOOD; + } - if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) - cmd->result = SAM_STAT_CHECK_CONDITION; - else { - u8 *scsicmd = cmd->cmnd; + } + 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(cmd, &buf); + buf[2] = 0x5; + buf[3] = (buf[3] & 0xf0) | 2; + ata_scsi_rbuf_put(cmd); + } + cmd->result = SAM_STAT_GOOD; + } + } + } + //end add by clear zhang 2004/12/7 + + else + { - if (scsicmd[0] == INQUIRY) { - u8 *buf = NULL; - unsigned int buflen; - - buflen = ata_scsi_rbuf_get(cmd, &buf); - buf[2] = 0x5; - buf[3] = (buf[3] & 0xf0) | 2; - ata_scsi_rbuf_put(cmd); + 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(cmd, &buf); + buf[2] = 0x5; + buf[3] = (buf[3] & 0xf0) | 2; + ata_scsi_rbuf_put(cmd); + } + cmd->result = SAM_STAT_GOOD; } - cmd->result = SAM_STAT_GOOD; } qc->scsidone(cmd);