Merge branch 'upstream-fixes' into upstream
authorJeff Garzik <jeff@garzik.org>
Wed, 24 May 2006 05:49:12 +0000 (01:49 -0400)
committerJeff Garzik <jeff@garzik.org>
Wed, 24 May 2006 05:49:12 +0000 (01:49 -0400)
Conflicts:

drivers/scsi/libata-core.c

1  2 
drivers/scsi/libata-core.c

index bf00d2b2e404c3d13cc7ef2896f86d339f8b8a6d,fa476e7e0a480c52f2808b721e3c465eb1ba5fc3..e891b83be10fd36e865549dd952f4f77d496e449
@@@ -3690,68 -3444,14 +3690,68 @@@ static void ata_pio_sector(struct ata_q
                qc->cursg++;
                qc->cursg_ofs = 0;
        }
 +}
  
 -      DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
 +/**
 + *    ata_pio_sectors - Transfer one or many 512-byte sectors.
 + *    @qc: Command on going
 + *
-  *    Transfer one or many ATA_SECT_SIZE of data from/to the 
++ *    Transfer one or many ATA_SECT_SIZE of data from/to the
 + *    ATA device for the DRQ request.
 + *
 + *    LOCKING:
 + *    Inherited from caller.
 + */
 +
 +static void ata_pio_sectors(struct ata_queued_cmd *qc)
 +{
 +      if (is_multi_taskfile(&qc->tf)) {
 +              /* READ/WRITE MULTIPLE */
 +              unsigned int nsect;
 +
 +              WARN_ON(qc->dev->multi_count == 0);
 +
 +              nsect = min(qc->nsect - qc->cursect, qc->dev->multi_count);
 +              while (nsect--)
 +                      ata_pio_sector(qc);
 +      } else
 +              ata_pio_sector(qc);
 +}
 +
 +/**
 + *    atapi_send_cdb - Write CDB bytes to hardware
 + *    @ap: Port to which ATAPI device is attached.
 + *    @qc: Taskfile currently active
 + *
 + *    When device has indicated its readiness to accept
 + *    a CDB, this function is called.  Send the CDB.
 + *
 + *    LOCKING:
 + *    caller.
 + */
  
 -      /* do the actual data transfer */
 -      do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
 -      ata_data_xfer(ap, buf, ATA_SECT_SIZE, do_write);
 +static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc)
 +{
 +      /* send SCSI cdb */
 +      DPRINTK("send cdb\n");
 +      WARN_ON(qc->dev->cdb_len < 12);
  
 -      kunmap(page);
 +      ata_data_xfer(ap, qc->cdb, qc->dev->cdb_len, 1);
 +      ata_altstatus(ap); /* flush */
 +
 +      switch (qc->tf.protocol) {
 +      case ATA_PROT_ATAPI:
 +              ap->hsm_task_state = HSM_ST;
 +              break;
 +      case ATA_PROT_ATAPI_NODATA:
 +              ap->hsm_task_state = HSM_ST_LAST;
 +              break;
 +      case ATA_PROT_ATAPI_DMA:
 +              ap->hsm_task_state = HSM_ST_LAST;
 +              /* initiate bmdma */
 +              ap->ops->bmdma_start(qc);
 +              break;
 +      }
  }
  
  /**
@@@ -3899,80 -3583,127 +3899,82 @@@ err_out
  }
  
  /**
 - *    ata_pio_block - start PIO on a block
 + *    ata_hsm_ok_in_wq - Check if the qc can be handled in the workqueue.
   *    @ap: the target ata_port
 + *    @qc: qc on going
   *
 - *    LOCKING:
 - *    None.  (executing in kernel thread context)
 + *    RETURNS:
 + *    1 if ok in workqueue, 0 otherwise.
   */
  
 -static void ata_pio_block(struct ata_port *ap)
 +static inline int ata_hsm_ok_in_wq(struct ata_port *ap, struct ata_queued_cmd *qc)
  {
 -      struct ata_queued_cmd *qc;
 -      u8 status;
 -
 -      /*
 -       * This is purely heuristic.  This is a fast path.
 -       * Sometimes when we enter, BSY will be cleared in
 -       * a chk-status or two.  If not, the drive is probably seeking
 -       * or something.  Snooze for a couple msecs, then
 -       * chk-status again.  If still busy, fall back to
 -       * HSM_ST_POLL state.
 -       */
 -      status = ata_busy_wait(ap, ATA_BUSY, 5);
 -      if (status & ATA_BUSY) {
 -              msleep(2);
 -              status = ata_busy_wait(ap, ATA_BUSY, 10);
 -              if (status & ATA_BUSY) {
 -                      ap->hsm_task_state = HSM_ST_POLL;
 -                      ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO;
 -                      return;
 -              }
 -      }
 +      if (qc->tf.flags & ATA_TFLAG_POLLING)
 +              return 1;
  
 -      qc = ata_qc_from_tag(ap, ap->active_tag);
 -      WARN_ON(qc == NULL);
 +      if (ap->hsm_task_state == HSM_ST_FIRST) {
 +              if (qc->tf.protocol == ATA_PROT_PIO &&
 +                  (qc->tf.flags & ATA_TFLAG_WRITE))
 +                  return 1;
  
 -      /* check error */
 -      if (status & (ATA_ERR | ATA_DF)) {
 -              qc->err_mask |= AC_ERR_DEV;
 -              ap->hsm_task_state = HSM_ST_ERR;
 -              return;
 +              if (is_atapi_taskfile(&qc->tf) &&
 +                  !(qc->dev->flags & ATA_DFLAG_CDB_INTR))
 +                      return 1;
        }
  
 -      /* transfer data if any */
 -      if (is_atapi_taskfile(&qc->tf)) {
 -              /* DRQ=0 means no more data to transfer */
 -              if ((status & ATA_DRQ) == 0) {
 -                      ap->hsm_task_state = HSM_ST_LAST;
 -                      return;
 -              }
 -
 -              atapi_pio_bytes(qc);
 -      } else {
 -              /* handle BSY=0, DRQ=0 as error */
 -              if ((status & ATA_DRQ) == 0) {
 -                      qc->err_mask |= AC_ERR_HSM;
 -                      ap->hsm_task_state = HSM_ST_ERR;
 -                      return;
 -              }
 -
 -              ata_pio_sector(qc);
 -      }
 -
 -      ata_altstatus(ap); /* flush */
 -}
 -
 -static void ata_pio_error(struct ata_port *ap)
 -{
 -      struct ata_queued_cmd *qc;
 -
 -      qc = ata_qc_from_tag(ap, ap->active_tag);
 -      WARN_ON(qc == NULL);
 -
 -      if (qc->tf.command != ATA_CMD_PACKET)
 -              printk(KERN_WARNING "ata%u: PIO error\n", ap->id);
 -
 -      /* make sure qc->err_mask is available to
 -       * know what's wrong and recover
 -       */
 -      WARN_ON(qc->err_mask == 0);
 -
 -      ap->hsm_task_state = HSM_ST_IDLE;
 -
 -      ata_poll_qc_complete(qc);
 +      return 0;
  }
  
 -static void ata_pio_task(void *_data)
 +/**
 + *    ata_hsm_qc_complete - finish a qc running on standard HSM
 + *    @qc: Command to complete
 + *    @in_wq: 1 if called from workqueue, 0 otherwise
 + *
 + *    Finish @qc which is running on standard HSM.
 + *
 + *    LOCKING:
 + *    If @in_wq is zero, spin_lock_irqsave(host_set lock).
 + *    Otherwise, none on entry and grabs host lock.
 + */
 +static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq)
  {
 -      struct ata_port *ap = _data;
 -      unsigned long timeout;
 -      int qc_completed;
 -
 -fsm_start:
 -      timeout = 0;
 -      qc_completed = 0;
 -
 -      switch (ap->hsm_task_state) {
 -      case HSM_ST_IDLE:
 -              return;
 -
 -      case HSM_ST:
 -              ata_pio_block(ap);
 -              break;
 +      struct ata_port *ap = qc->ap;
 +      unsigned long flags;
  
 -      case HSM_ST_LAST:
 -              qc_completed = ata_pio_complete(ap);
 -              break;
 +      if (ap->ops->error_handler) {
 +              if (in_wq) {
 +                      spin_lock_irqsave(&ap->host_set->lock, flags);
  
 -      case HSM_ST_POLL:
 -      case HSM_ST_LAST_POLL:
 -              timeout = ata_pio_poll(ap);
 -              break;
 +                      /* EH might have kicked in while host_set lock
 +                       * is released.
 +                       */
 +                      qc = ata_qc_from_tag(ap, qc->tag);
 +                      if (qc) {
 +                              if (likely(!(qc->err_mask & AC_ERR_HSM))) {
 +                                      ata_irq_on(ap);
 +                                      ata_qc_complete(qc);
 +                              } else
 +                                      ata_port_freeze(ap);
 +                      }
  
 -      case HSM_ST_TMOUT:
 -      case HSM_ST_ERR:
 -              ata_pio_error(ap);
 -              return;
 +                      spin_unlock_irqrestore(&ap->host_set->lock, flags);
 +              } else {
 +                      if (likely(!(qc->err_mask & AC_ERR_HSM)))
 +                              ata_qc_complete(qc);
 +                      else
 +                              ata_port_freeze(ap);
 +              }
 +      } else {
 +              if (in_wq) {
 +                      spin_lock_irqsave(&ap->host_set->lock, flags);
 +                      ata_irq_on(ap);
 +                      ata_qc_complete(qc);
 +                      spin_unlock_irqrestore(&ap->host_set->lock, flags);
 +              } else
 +                      ata_qc_complete(qc);
        }
 -      if (timeout)
 -              ata_port_queue_task(ap, ata_pio_task, ap, timeout);
 -      else if (!qc_completed)
 -              goto fsm_start;
++      ata_altstatus(ap); /* flush */
  }
  
  /**