]> git.karo-electronics.de Git - linux-beck.git/blobdiff - drivers/scsi/libata-core.c
Merge branch 'upstream'
[linux-beck.git] / drivers / scsi / libata-core.c
index 9aa93087d495643c042b658916a21f59adca86f1..c5e663fefdf7a7aee17cafa44add1b02e65ecc2c 100644 (file)
@@ -63,6 +63,7 @@
 static unsigned int ata_busy_sleep (struct ata_port *ap,
                                    unsigned long tmout_pat,
                                    unsigned long tmout);
+static void ata_dev_reread_id(struct ata_port *ap, struct ata_device *dev);
 static void ata_dev_init_params(struct ata_port *ap, struct ata_device *dev);
 static void ata_set_mode(struct ata_port *ap);
 static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev);
@@ -616,79 +617,53 @@ void ata_tf_from_fis(u8 *fis, struct ata_taskfile *tf)
        tf->hob_nsect   = fis[13];
 }
 
-/**
- *     ata_prot_to_cmd - determine which read/write opcodes to use
- *     @protocol: ATA_PROT_xxx taskfile protocol
- *     @lba48: true is lba48 is present
- *
- *     Given necessary input, determine which read/write commands
- *     to use to transfer data.
- *
- *     LOCKING:
- *     None.
- */
-static int ata_prot_to_cmd(int protocol, int lba48)
-{
-       int rcmd = 0, wcmd = 0;
-
-       switch (protocol) {
-       case ATA_PROT_PIO:
-               if (lba48) {
-                       rcmd = ATA_CMD_PIO_READ_EXT;
-                       wcmd = ATA_CMD_PIO_WRITE_EXT;
-               } else {
-                       rcmd = ATA_CMD_PIO_READ;
-                       wcmd = ATA_CMD_PIO_WRITE;
-               }
-               break;
-
-       case ATA_PROT_DMA:
-               if (lba48) {
-                       rcmd = ATA_CMD_READ_EXT;
-                       wcmd = ATA_CMD_WRITE_EXT;
-               } else {
-                       rcmd = ATA_CMD_READ;
-                       wcmd = ATA_CMD_WRITE;
-               }
-               break;
-
-       default:
-               return -1;
-       }
-
-       return rcmd | (wcmd << 8);
-}
+static const u8 ata_rw_cmds[] = {
+       /* pio multi */
+       ATA_CMD_READ_MULTI,
+       ATA_CMD_WRITE_MULTI,
+       ATA_CMD_READ_MULTI_EXT,
+       ATA_CMD_WRITE_MULTI_EXT,
+       /* pio */
+       ATA_CMD_PIO_READ,
+       ATA_CMD_PIO_WRITE,
+       ATA_CMD_PIO_READ_EXT,
+       ATA_CMD_PIO_WRITE_EXT,
+       /* dma */
+       ATA_CMD_READ,
+       ATA_CMD_WRITE,
+       ATA_CMD_READ_EXT,
+       ATA_CMD_WRITE_EXT
+};
 
 /**
- *     ata_dev_set_protocol - set taskfile protocol and r/w commands
- *     @dev: device to examine and configure
+ *     ata_rwcmd_protocol - set taskfile r/w commands and protocol
+ *     @qc: command to examine and configure
  *
- *     Examine the device configuration, after we have
- *     read the identify-device page and configured the
- *     data transfer mode.  Set internal state related to
- *     the ATA taskfile protocol (pio, pio mult, dma, etc.)
- *     and calculate the proper read/write commands to use.
+ *     Examine the device configuration and tf->flags to calculate 
+ *     the proper read/write commands and protocol to use.
  *
  *     LOCKING:
  *     caller.
  */
-static void ata_dev_set_protocol(struct ata_device *dev)
+void ata_rwcmd_protocol(struct ata_queued_cmd *qc)
 {
-       int pio = (dev->flags & ATA_DFLAG_PIO);
-       int lba48 = (dev->flags & ATA_DFLAG_LBA48);
-       int proto, cmd;
+       struct ata_taskfile *tf = &qc->tf;
+       struct ata_device *dev = qc->dev;
 
-       if (pio)
-               proto = dev->xfer_protocol = ATA_PROT_PIO;
-       else
-               proto = dev->xfer_protocol = ATA_PROT_DMA;
+       int index, lba48, write;
+       lba48 = (tf->flags & ATA_TFLAG_LBA48) ? 2 : 0;
+       write = (tf->flags & ATA_TFLAG_WRITE) ? 1 : 0;
 
-       cmd = ata_prot_to_cmd(proto, lba48);
-       if (cmd < 0)
-               BUG();
+       if (dev->flags & ATA_DFLAG_PIO) {
+               tf->protocol = ATA_PROT_PIO;
+               index = dev->multi_count ? 0 : 4;
+       } else {
+               tf->protocol = ATA_PROT_DMA;
+               index = 8;
+       }
 
-       dev->read_cmd = cmd & 0xff;
-       dev->write_cmd = (cmd >> 8) & 0xff;
+       tf->command = ata_rw_cmds[index + lba48 + write];
 }
 
 static const char * xfer_mode_str[] = {
@@ -1266,9 +1241,15 @@ retry:
                 * anything else..
                 * Some drives were very specific about that exact sequence.
                 */
-               if (major_version < 4 || (!ata_id_has_lba(dev->id)))
+               if (major_version < 4 || (!ata_id_has_lba(dev->id))) {
                        ata_dev_init_params(ap, dev);
 
+                       /* current CHS translation info (id[53-58]) might be
+                        * changed. reread the identify device info.
+                        */
+                       ata_dev_reread_id(ap, dev);
+               }
+
                if (ata_id_has_lba(dev->id)) {
                        dev->flags |= ATA_DFLAG_LBA;
 
@@ -1641,7 +1622,7 @@ static void ata_host_set_dma(struct ata_port *ap, u8 xfer_mode,
  */
 static void ata_set_mode(struct ata_port *ap)
 {
-       unsigned int i, xfer_shift;
+       unsigned int xfer_shift;
        u8 xfer_mode;
        int rc;
 
@@ -1670,11 +1651,6 @@ static void ata_set_mode(struct ata_port *ap)
        if (ap->ops->post_set_mode)
                ap->ops->post_set_mode(ap);
 
-       for (i = 0; i < 2; i++) {
-               struct ata_device *dev = &ap->device[i];
-               ata_dev_set_protocol(dev);
-       }
-
        return;
 
 err_out:
@@ -2181,6 +2157,62 @@ static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev)
        DPRINTK("EXIT\n");
 }
 
+/**
+ *     ata_dev_reread_id - Reread the device identify device info
+ *     @ap: port where the device is
+ *     @dev: device to reread the identify device info
+ *
+ *     LOCKING:
+ */
+
+static void ata_dev_reread_id(struct ata_port *ap, struct ata_device *dev)
+{
+       DECLARE_COMPLETION(wait);
+       struct ata_queued_cmd *qc;
+       unsigned long flags;
+       int rc;
+
+       qc = ata_qc_new_init(ap, dev);
+       BUG_ON(qc == NULL);
+
+       ata_sg_init_one(qc, dev->id, sizeof(dev->id));
+       qc->dma_dir = DMA_FROM_DEVICE;
+
+       if (dev->class == ATA_DEV_ATA) {
+               qc->tf.command = ATA_CMD_ID_ATA;
+               DPRINTK("do ATA identify\n");
+       } else {
+               qc->tf.command = ATA_CMD_ID_ATAPI;
+               DPRINTK("do ATAPI identify\n");
+       }
+
+       qc->tf.flags |= ATA_TFLAG_DEVICE;
+       qc->tf.protocol = ATA_PROT_PIO;
+       qc->nsect = 1;
+
+       qc->waiting = &wait;
+       qc->complete_fn = ata_qc_complete_noop;
+
+       spin_lock_irqsave(&ap->host_set->lock, flags);
+       rc = ata_qc_issue(qc);
+       spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+       if (rc)
+               goto err_out;
+
+       wait_for_completion(&wait);
+
+       swap_buf_le16(dev->id, ATA_ID_WORDS);
+
+       ata_dump_id(dev);
+
+       DPRINTK("EXIT\n");
+
+       return;
+err_out:
+       ata_port_disable(ap);
+}
+
 /**
  *     ata_dev_init_params - Issue INIT DEV PARAMS command
  *     @ap: Port associated with device @dev
@@ -3277,13 +3309,6 @@ struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
                qc->nbytes = qc->curbytes = 0;
 
                ata_tf_init(ap, &qc->tf, dev->devno);
-
-               if (dev->flags & ATA_DFLAG_LBA) {
-                       qc->tf.flags |= ATA_TFLAG_LBA;
-
-                       if (dev->flags & ATA_DFLAG_LBA48)
-                               qc->tf.flags |= ATA_TFLAG_LBA48;
-               }
        }
 
        return qc;