]> git.karo-electronics.de Git - linux-beck.git/commitdiff
Merge branch 'upstream-fixes'
authorJeff Garzik <jeff@garzik.org>
Sun, 12 Mar 2006 00:10:06 +0000 (19:10 -0500)
committerJeff Garzik <jeff@garzik.org>
Sun, 12 Mar 2006 00:10:06 +0000 (19:10 -0500)
1  2 
drivers/scsi/ahci.c

diff --combined drivers/scsi/ahci.c
index 1c2ab3dede71726c8fe31b698591bbb234c78181,559ff7aae3f113e4f61e551050c289b73f7fa6d6..00dfdefe2967fccbf6fd45897ea1d3e288b1839f
@@@ -66,8 -66,6 +66,8 @@@ enum 
        AHCI_IRQ_ON_SG          = (1 << 31),
        AHCI_CMD_ATAPI          = (1 << 5),
        AHCI_CMD_WRITE          = (1 << 6),
 +      AHCI_CMD_RESET          = (1 << 8),
 +      AHCI_CMD_CLR_BUSY       = (1 << 10),
  
        RX_FIS_D2H_REG          = 0x40, /* offset of D2H Register FIS data */
  
@@@ -87,7 -85,6 +87,7 @@@
  
        /* HOST_CAP bits */
        HOST_CAP_64             = (1 << 31), /* PCI DAC (64-bit DMA) support */
 +      HOST_CAP_CLO            = (1 << 24), /* Command List Override support */
  
        /* registers for each SATA port */
        PORT_LST_ADDR           = 0x00, /* command list DMA addr */
        PORT_CMD_LIST_ON        = (1 << 15), /* cmd list DMA engine running */
        PORT_CMD_FIS_ON         = (1 << 14), /* FIS DMA engine running */
        PORT_CMD_FIS_RX         = (1 << 4), /* Enable FIS receive DMA engine */
 +      PORT_CMD_CLO            = (1 << 3), /* Command list override */
        PORT_CMD_POWER_ON       = (1 << 2), /* Power up device */
        PORT_CMD_SPIN_UP        = (1 << 1), /* Spin up device */
        PORT_CMD_START          = (1 << 0), /* Enable port DMA engine */
@@@ -188,9 -184,9 +188,9 @@@ struct ahci_port_priv 
  static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg);
  static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
  static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
 -static int ahci_qc_issue(struct ata_queued_cmd *qc);
 +static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
  static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
 -static void ahci_phy_reset(struct ata_port *ap);
 +static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes);
  static void ahci_irq_clear(struct ata_port *ap);
  static void ahci_eng_timeout(struct ata_port *ap);
  static int ahci_port_start(struct ata_port *ap);
@@@ -206,11 -202,11 +206,11 @@@ static struct scsi_host_template ahci_s
        .name                   = DRV_NAME,
        .ioctl                  = ata_scsi_ioctl,
        .queuecommand           = ata_scsi_queuecmd,
 +      .eh_timed_out           = ata_scsi_timed_out,
        .eh_strategy_handler    = ata_scsi_error,
        .can_queue              = ATA_DEF_QUEUE,
        .this_id                = ATA_SHT_THIS_ID,
        .sg_tablesize           = AHCI_MAX_SG,
 -      .max_sectors            = ATA_MAX_SECTORS,
        .cmd_per_lun            = ATA_SHT_CMD_PER_LUN,
        .emulated               = ATA_SHT_EMULATED,
        .use_clustering         = AHCI_USE_CLUSTERING,
@@@ -229,7 -225,7 +229,7 @@@ static const struct ata_port_operation
  
        .tf_read                = ahci_tf_read,
  
 -      .phy_reset              = ahci_phy_reset,
 +      .probe_reset            = ahci_probe_reset,
  
        .qc_prep                = ahci_qc_prep,
        .qc_issue               = ahci_qc_issue,
@@@ -251,7 -247,8 +251,7 @@@ static const struct ata_port_info ahci_
        {
                .sht            = &ahci_sht,
                .host_flags     = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
 -                                ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
 -                                ATA_FLAG_PIO_DMA,
 +                                ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
                .pio_mask       = 0x1f, /* pio0-4 */
                .udma_mask      = 0x7f, /* udma0-6 ; FIXME */
                .port_ops       = &ahci_ops,
@@@ -453,48 -450,17 +453,48 @@@ static void ahci_scr_write (struct ata_
        writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
  }
  
 -static void ahci_phy_reset(struct ata_port *ap)
 +static int ahci_stop_engine(struct ata_port *ap)
  {
 -      void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
 -      struct ata_taskfile tf;
 -      struct ata_device *dev = &ap->device[0];
 -      u32 new_tmp, tmp;
 +      void __iomem *mmio = ap->host_set->mmio_base;
 +      void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
 +      int work;
 +      u32 tmp;
  
 -      __sata_phy_reset(ap);
 +      tmp = readl(port_mmio + PORT_CMD);
 +      tmp &= ~PORT_CMD_START;
 +      writel(tmp, port_mmio + PORT_CMD);
  
 -      if (ap->flags & ATA_FLAG_PORT_DISABLED)
 -              return;
 +      /* wait for engine to stop.  TODO: this could be
 +       * as long as 500 msec
 +       */
 +      work = 1000;
 +      while (work-- > 0) {
 +              tmp = readl(port_mmio + PORT_CMD);
 +              if ((tmp & PORT_CMD_LIST_ON) == 0)
 +                      return 0;
 +              udelay(10);
 +      }
 +
 +      return -EIO;
 +}
 +
 +static void ahci_start_engine(struct ata_port *ap)
 +{
 +      void __iomem *mmio = ap->host_set->mmio_base;
 +      void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
 +      u32 tmp;
 +
 +      tmp = readl(port_mmio + PORT_CMD);
 +      tmp |= PORT_CMD_START;
 +      writel(tmp, port_mmio + PORT_CMD);
 +      readl(port_mmio + PORT_CMD); /* flush */
 +}
 +
 +static unsigned int ahci_dev_classify(struct ata_port *ap)
 +{
 +      void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
 +      struct ata_taskfile tf;
 +      u32 tmp;
  
        tmp = readl(port_mmio + PORT_SIG);
        tf.lbah         = (tmp >> 24)   & 0xff;
        tf.lbal         = (tmp >> 8)    & 0xff;
        tf.nsect        = (tmp)         & 0xff;
  
 -      dev->class = ata_dev_classify(&tf);
 -      if (!ata_dev_present(dev)) {
 -              ata_port_disable(ap);
 -              return;
 -      }
 +      return ata_dev_classify(&tf);
 +}
 +
 +static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, u32 opts)
 +{
 +      pp->cmd_slot[0].opts = cpu_to_le32(opts);
 +      pp->cmd_slot[0].status = 0;
 +      pp->cmd_slot[0].tbl_addr = cpu_to_le32(pp->cmd_tbl_dma & 0xffffffff);
 +      pp->cmd_slot[0].tbl_addr_hi = cpu_to_le32((pp->cmd_tbl_dma >> 16) >> 16);
 +}
 +
 +static int ahci_hardreset(struct ata_port *ap, int verbose, unsigned int *class)
 +{
 +      int rc;
 +
 +      DPRINTK("ENTER\n");
 +
 +      ahci_stop_engine(ap);
 +      rc = sata_std_hardreset(ap, verbose, class);
 +      ahci_start_engine(ap);
 +
 +      if (rc == 0)
 +              *class = ahci_dev_classify(ap);
 +      if (*class == ATA_DEV_UNKNOWN)
 +              *class = ATA_DEV_NONE;
 +
 +      DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
 +      return rc;
 +}
 +
 +static void ahci_postreset(struct ata_port *ap, unsigned int *class)
 +{
 +      void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
 +      u32 new_tmp, tmp;
 +
 +      ata_std_postreset(ap, class);
  
        /* Make sure port's ATAPI bit is set appropriately */
        new_tmp = tmp = readl(port_mmio + PORT_CMD);
 -      if (dev->class == ATA_DEV_ATAPI)
 +      if (*class == ATA_DEV_ATAPI)
                new_tmp |= PORT_CMD_ATAPI;
        else
                new_tmp &= ~PORT_CMD_ATAPI;
        }
  }
  
 +static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes)
 +{
 +      return ata_drive_probe_reset(ap, NULL, NULL, ahci_hardreset,
 +                                   ahci_postreset, classes);
 +}
 +
  static u8 ahci_check_status(struct ata_port *ap)
  {
        void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr;
@@@ -604,36 -533,42 +604,36 @@@ static void ahci_qc_prep(struct ata_que
  {
        struct ata_port *ap = qc->ap;
        struct ahci_port_priv *pp = ap->private_data;
 +      int is_atapi = is_atapi_taskfile(&qc->tf);
        u32 opts;
        const u32 cmd_fis_len = 5; /* five dwords */
        unsigned int n_elem;
  
 -      /*
 -       * Fill in command slot information (currently only one slot,
 -       * slot 0, is currently since we don't do queueing)
 -       */
 -
 -      opts = cmd_fis_len;
 -      if (qc->tf.flags & ATA_TFLAG_WRITE)
 -              opts |= AHCI_CMD_WRITE;
 -      if (is_atapi_taskfile(&qc->tf))
 -              opts |= AHCI_CMD_ATAPI;
 -
 -      pp->cmd_slot[0].opts = cpu_to_le32(opts);
 -      pp->cmd_slot[0].status = 0;
 -      pp->cmd_slot[0].tbl_addr = cpu_to_le32(pp->cmd_tbl_dma & 0xffffffff);
 -      pp->cmd_slot[0].tbl_addr_hi = cpu_to_le32((pp->cmd_tbl_dma >> 16) >> 16);
 -
        /*
         * Fill in command table information.  First, the header,
         * a SATA Register - Host to Device command FIS.
         */
        ata_tf_to_fis(&qc->tf, pp->cmd_tbl, 0);
 -      if (opts & AHCI_CMD_ATAPI) {
 +      if (is_atapi) {
                memset(pp->cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
 -              memcpy(pp->cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, ap->cdb_len);
 +              memcpy(pp->cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb,
 +                     qc->dev->cdb_len);
        }
  
 -      if (!(qc->flags & ATA_QCFLAG_DMAMAP))
 -              return;
 +      n_elem = 0;
 +      if (qc->flags & ATA_QCFLAG_DMAMAP)
 +              n_elem = ahci_fill_sg(qc);
  
 -      n_elem = ahci_fill_sg(qc);
 +      /*
 +       * Fill in command slot information.
 +       */
 +      opts = cmd_fis_len | n_elem << 16;
 +      if (qc->tf.flags & ATA_TFLAG_WRITE)
 +              opts |= AHCI_CMD_WRITE;
 +      if (is_atapi)
 +              opts |= AHCI_CMD_ATAPI;
  
 -      pp->cmd_slot[0].opts |= cpu_to_le32(n_elem << 16);
 +      ahci_fill_cmd_slot(pp, opts);
  }
  
  static void ahci_restart_port(struct ata_port *ap, u32 irq_stat)
        void __iomem *mmio = ap->host_set->mmio_base;
        void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
        u32 tmp;
 -      int work;
  
        if ((ap->device[0].class != ATA_DEV_ATAPI) ||
            ((irq_stat & PORT_IRQ_TF_ERR) == 0))
                        readl(port_mmio + PORT_SCR_ERR));
  
        /* stop DMA */
 -      tmp = readl(port_mmio + PORT_CMD);
 -      tmp &= ~PORT_CMD_START;
 -      writel(tmp, port_mmio + PORT_CMD);
 -
 -      /* wait for engine to stop.  TODO: this could be
 -       * as long as 500 msec
 -       */
 -      work = 1000;
 -      while (work-- > 0) {
 -              tmp = readl(port_mmio + PORT_CMD);
 -              if ((tmp & PORT_CMD_LIST_ON) == 0)
 -                      break;
 -              udelay(10);
 -      }
 +      ahci_stop_engine(ap);
  
        /* clear SATA phy error, if any */
        tmp = readl(port_mmio + PORT_SCR_ERR);
        }
  
        /* re-start DMA */
 -      tmp = readl(port_mmio + PORT_CMD);
 -      tmp |= PORT_CMD_START;
 -      writel(tmp, port_mmio + PORT_CMD);
 -      readl(port_mmio + PORT_CMD); /* flush */
 +      ahci_start_engine(ap);
  }
  
  static void ahci_eng_timeout(struct ata_port *ap)
  
        spin_lock_irqsave(&host_set->lock, flags);
  
 +      ahci_restart_port(ap, readl(port_mmio + PORT_IRQ_STAT));
        qc = ata_qc_from_tag(ap, ap->active_tag);
 -      if (!qc) {
 -              printk(KERN_ERR "ata%u: BUG: timeout without command\n",
 -                     ap->id);
 -      } else {
 -              ahci_restart_port(ap, readl(port_mmio + PORT_IRQ_STAT));
 -
 -              /* 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;
 -              qc->err_mask |= AC_ERR_OTHER;
 -              ata_qc_complete(qc);
 -      }
 +      qc->err_mask |= AC_ERR_TIMEOUT;
  
        spin_unlock_irqrestore(&host_set->lock, flags);
 +
 +      ata_eh_qc_complete(qc);
  }
  
  static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
        ci = readl(port_mmio + PORT_CMD_ISSUE);
        if (likely((ci & 0x1) == 0)) {
                if (qc) {
 -                      assert(qc->err_mask == 0);
 +                      WARN_ON(qc->err_mask);
                        ata_qc_complete(qc);
                        qc = NULL;
                }
                ahci_restart_port(ap, status);
  
                if (qc) {
 -                      qc->err_mask |= AC_ERR_OTHER;
 +                      qc->err_mask |= err_mask;
                        ata_qc_complete(qc);
                }
        }
@@@ -778,23 -742,17 +778,17 @@@ static irqreturn_t ahci_interrupt (int 
                        struct ata_queued_cmd *qc;
                        qc = ata_qc_from_tag(ap, ap->active_tag);
                        if (!ahci_host_intr(ap, qc))
-                               if (ata_ratelimit()) {
-                                       struct pci_dev *pdev =
-                                               to_pci_dev(ap->host_set->dev);
-                                       dev_printk(KERN_WARNING, &pdev->dev,
+                               if (ata_ratelimit())
+                                       dev_printk(KERN_WARNING, host_set->dev,
                                          "unhandled interrupt on port %u\n",
                                          i);
-                               }
  
                        VPRINTK("port %u\n", i);
                } else {
                        VPRINTK("port %u (no irq)\n", i);
-                       if (ata_ratelimit()) {
-                               struct pci_dev *pdev =
-                                       to_pci_dev(ap->host_set->dev);
-                               dev_printk(KERN_WARNING, &pdev->dev,
+                       if (ata_ratelimit())
+                               dev_printk(KERN_WARNING, host_set->dev,
                                        "interrupt on disabled port %u\n", i);
-                       }
                }
  
                irq_ack |= (1 << i);
        return IRQ_RETVAL(handled);
  }
  
 -static int ahci_qc_issue(struct ata_queued_cmd *qc)
 +static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
  {
        struct ata_port *ap = qc->ap;
        void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;