[PATCH] libata: implement ata_tf_read_block()
[linux-2.6.git] / drivers / ata / libata-core.c
index d94b8a0..3fd7c79 100644 (file)
@@ -240,6 +240,49 @@ int ata_rwcmd_protocol(struct ata_queued_cmd *qc)
 }
 
 /**
+ *     ata_tf_read_block - Read block address from ATA taskfile
+ *     @tf: ATA taskfile of interest
+ *     @dev: ATA device @tf belongs to
+ *
+ *     LOCKING:
+ *     None.
+ *
+ *     Read block address from @tf.  This function can handle all
+ *     three address formats - LBA, LBA48 and CHS.  tf->protocol and
+ *     flags select the address format to use.
+ *
+ *     RETURNS:
+ *     Block address read from @tf.
+ */
+u64 ata_tf_read_block(struct ata_taskfile *tf, struct ata_device *dev)
+{
+       u64 block = 0;
+
+       if (tf->flags & ATA_TFLAG_LBA) {
+               if (tf->flags & ATA_TFLAG_LBA48) {
+                       block |= (u64)tf->hob_lbah << 40;
+                       block |= (u64)tf->hob_lbam << 32;
+                       block |= tf->hob_lbal << 24;
+               } else
+                       block |= (tf->device & 0xf) << 24;
+
+               block |= tf->lbah << 16;
+               block |= tf->lbam << 8;
+               block |= tf->lbal;
+       } else {
+               u32 cyl, head, sect;
+
+               cyl = tf->lbam | (tf->lbah << 8);
+               head = tf->device & 0xf;
+               sect = tf->lbal;
+
+               block = (cyl * dev->heads + head) * dev->sectors + sect;
+       }
+
+       return block;
+}
+
+/**
  *     ata_pack_xfermask - Pack pio, mwdma and udma masks into xfer_mask
  *     @pio_mask: pio_mask
  *     @mwdma_mask: mwdma_mask
@@ -1224,7 +1267,7 @@ unsigned int ata_pio_need_iordy(const struct ata_device *adev)
  *     ata_dev_read_id - Read ID data from the specified device
  *     @dev: target device
  *     @p_class: pointer to class of the target device (may be changed)
- *     @post_reset: is this read ID post-reset?
+ *     @flags: ATA_READID_* flags
  *     @id: buffer to read IDENTIFY data into
  *
  *     Read ID data from the specified device.  ATA_CMD_ID_ATA is
@@ -1239,7 +1282,7 @@ unsigned int ata_pio_need_iordy(const struct ata_device *adev)
  *     0 on success, -errno otherwise.
  */
 int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
-                   int post_reset, u16 *id)
+                   unsigned int flags, u16 *id)
 {
        struct ata_port *ap = dev->ap;
        unsigned int class = *p_class;
@@ -1272,9 +1315,20 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
 
        tf.protocol = ATA_PROT_PIO;
 
+       /* presence detection using polling IDENTIFY? */
+       if (flags & ATA_READID_DETECT)
+               tf.flags |= ATA_TFLAG_POLLING;
+
        err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
                                     id, sizeof(id[0]) * ATA_ID_WORDS);
        if (err_mask) {
+               if ((flags & ATA_READID_DETECT) &&
+                   (err_mask & AC_ERR_NODEV_HINT)) {
+                       DPRINTK("ata%u.%d: NODEV after polling detection\n",
+                               ap->id, dev->devno);
+                       return -ENOENT;
+               }
+
                rc = -EIO;
                reason = "I/O error";
                goto err_out;
@@ -1294,7 +1348,7 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
                        goto err_out;
        }
 
-       if (post_reset && class == ATA_DEV_ATA) {
+       if ((flags & ATA_READID_POSTRESET) && class == ATA_DEV_ATA) {
                /*
                 * The exact sequence expected by certain pre-ATA4 drives is:
                 * SRST RESET
@@ -1314,7 +1368,7 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
                        /* current CHS translation info (id[53-58]) might be
                         * changed. reread the identify device info.
                         */
-                       post_reset = 0;
+                       flags &= ~ATA_READID_POSTRESET;
                        goto retry;
                }
        }
@@ -1643,7 +1697,8 @@ int ata_bus_probe(struct ata_port *ap)
                if (!ata_dev_enabled(dev))
                        continue;
 
-               rc = ata_dev_read_id(dev, &dev->class, 1, dev->id);
+               rc = ata_dev_read_id(dev, &dev->class, ATA_READID_POSTRESET,
+                                    dev->id);
                if (rc)
                        goto fail;
 
@@ -3023,7 +3078,7 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class,
 /**
  *     ata_dev_revalidate - Revalidate ATA device
  *     @dev: device to revalidate
- *     @post_reset: is this revalidation after reset?
+ *     @readid_flags: read ID flags
  *
  *     Re-read IDENTIFY page and make sure @dev is still attached to
  *     the port.
@@ -3034,7 +3089,7 @@ static int ata_dev_same_device(struct ata_device *dev, unsigned int new_class,
  *     RETURNS:
  *     0 on success, negative errno otherwise
  */
-int ata_dev_revalidate(struct ata_device *dev, int post_reset)
+int ata_dev_revalidate(struct ata_device *dev, unsigned int readid_flags)
 {
        unsigned int class = dev->class;
        u16 *id = (void *)dev->ap->sector_buf;
@@ -3046,7 +3101,7 @@ int ata_dev_revalidate(struct ata_device *dev, int post_reset)
        }
 
        /* read ID data */
-       rc = ata_dev_read_id(dev, &class, post_reset, id);
+       rc = ata_dev_read_id(dev, &class, readid_flags, id);
        if (rc)
                goto fail;
 
@@ -3479,19 +3534,15 @@ void ata_noop_qc_prep(struct ata_queued_cmd *qc) { }
 
 void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen)
 {
-       struct scatterlist *sg;
-
        qc->flags |= ATA_QCFLAG_SINGLE;
 
-       memset(&qc->sgent, 0, sizeof(qc->sgent));
        qc->__sg = &qc->sgent;
        qc->n_elem = 1;
        qc->orig_n_elem = 1;
        qc->buf_virt = buf;
        qc->nbytes = buflen;
 
-       sg = qc->__sg;
-       sg_init_one(sg, buf, buflen);
+       sg_init_one(&qc->sgent, buf, buflen);
 }
 
 /**
@@ -4284,8 +4335,12 @@ fsm_start:
                                        /* device stops HSM for abort/error */
                                        qc->err_mask |= AC_ERR_DEV;
                                else
-                                       /* HSM violation. Let EH handle this */
-                                       qc->err_mask |= AC_ERR_HSM;
+                                       /* HSM violation. Let EH handle this.
+                                        * Phantom devices also trigger this
+                                        * condition.  Mark hint.
+                                        */
+                                       qc->err_mask |= AC_ERR_HSM |
+                                                       AC_ERR_NODEV_HINT;
 
                                ap->hsm_task_state = HSM_ST_ERR;
                                goto fsm_start;
@@ -4524,6 +4579,14 @@ void __ata_qc_complete(struct ata_queued_cmd *qc)
        qc->complete_fn(qc);
 }
 
+static void fill_result_tf(struct ata_queued_cmd *qc)
+{
+       struct ata_port *ap = qc->ap;
+
+       ap->ops->tf_read(ap, &qc->result_tf);
+       qc->result_tf.flags = qc->tf.flags;
+}
+
 /**
  *     ata_qc_complete - Complete an active ATA command
  *     @qc: Command to complete
@@ -4561,7 +4624,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
                if (unlikely(qc->flags & ATA_QCFLAG_FAILED)) {
                        if (!ata_tag_internal(qc->tag)) {
                                /* always fill result TF for failed qc */
-                               ap->ops->tf_read(ap, &qc->result_tf);
+                               fill_result_tf(qc);
                                ata_qc_schedule_eh(qc);
                                return;
                        }
@@ -4569,7 +4632,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
 
                /* read result TF if requested */
                if (qc->flags & ATA_QCFLAG_RESULT_TF)
-                       ap->ops->tf_read(ap, &qc->result_tf);
+                       fill_result_tf(qc);
 
                __ata_qc_complete(qc);
        } else {
@@ -4578,7 +4641,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
 
                /* read result TF if failed or requested */
                if (qc->err_mask || qc->flags & ATA_QCFLAG_RESULT_TF)
-                       ap->ops->tf_read(ap, &qc->result_tf);
+                       fill_result_tf(qc);
 
                __ata_qc_complete(qc);
        }