Commit 8cbd6df1 authored by Albert Lee's avatar Albert Lee Committed by Jeff Garzik

[PATCH] libata CHS: calculate read/write commands and protocol on the fly (revise #6)

     - merge ata_prot_to_cmd() and ata_dev_set_protocol() as
       ata_rwcmd_protocol()
     - pave road for read/write multiple support
     - remove usage of pre-cached command and protocol values and call
       ata_rwcmd_protocol() instead
Signed-off-by: default avatarAlbert Lee <albertcc@tw.ibm.com>

==============
Signed-off-by: default avatarJeff Garzik <jgarzik@pobox.com>
parent 07506697
...@@ -616,79 +616,53 @@ void ata_tf_from_fis(u8 *fis, struct ata_taskfile *tf) ...@@ -616,79 +616,53 @@ void ata_tf_from_fis(u8 *fis, struct ata_taskfile *tf)
tf->hob_nsect = fis[13]; tf->hob_nsect = fis[13];
} }
/** static const u8 ata_rw_cmds[] = {
* ata_prot_to_cmd - determine which read/write opcodes to use /* pio multi */
* @protocol: ATA_PROT_xxx taskfile protocol ATA_CMD_READ_MULTI,
* @lba48: true is lba48 is present ATA_CMD_WRITE_MULTI,
* ATA_CMD_READ_MULTI_EXT,
* Given necessary input, determine which read/write commands ATA_CMD_WRITE_MULTI_EXT,
* to use to transfer data. /* pio */
* ATA_CMD_PIO_READ,
* LOCKING: ATA_CMD_PIO_WRITE,
* None. ATA_CMD_PIO_READ_EXT,
*/ ATA_CMD_PIO_WRITE_EXT,
static int ata_prot_to_cmd(int protocol, int lba48) /* dma */
{ ATA_CMD_READ,
int rcmd = 0, wcmd = 0; ATA_CMD_WRITE,
ATA_CMD_READ_EXT,
switch (protocol) { ATA_CMD_WRITE_EXT
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);
}
/** /**
* ata_dev_set_protocol - set taskfile protocol and r/w commands * ata_rwcmd_protocol - set taskfile r/w commands and protocol
* @dev: device to examine and configure * @qc: command to examine and configure
* *
* Examine the device configuration, after we have * Examine the device configuration and tf->flags to calculate
* read the identify-device page and configured the * the proper read/write commands and protocol to use.
* 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.
* *
* LOCKING: * LOCKING:
* caller. * 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); struct ata_taskfile *tf = &qc->tf;
int lba48 = (dev->flags & ATA_DFLAG_LBA48); struct ata_device *dev = qc->dev;
int proto, cmd;
if (pio) int index, lba48, write;
proto = dev->xfer_protocol = ATA_PROT_PIO;
else lba48 = (tf->flags & ATA_TFLAG_LBA48) ? 2 : 0;
proto = dev->xfer_protocol = ATA_PROT_DMA; write = (tf->flags & ATA_TFLAG_WRITE) ? 1 : 0;
cmd = ata_prot_to_cmd(proto, lba48); if (dev->flags & ATA_DFLAG_PIO) {
if (cmd < 0) tf->protocol = ATA_PROT_PIO;
BUG(); index = dev->multi_count ? 0 : 4;
} else {
tf->protocol = ATA_PROT_DMA;
index = 8;
}
dev->read_cmd = cmd & 0xff; tf->command = ata_rw_cmds[index + lba48 + write];
dev->write_cmd = (cmd >> 8) & 0xff;
} }
static const char * xfer_mode_str[] = { static const char * xfer_mode_str[] = {
...@@ -1641,7 +1615,7 @@ static void ata_host_set_dma(struct ata_port *ap, u8 xfer_mode, ...@@ -1641,7 +1615,7 @@ static void ata_host_set_dma(struct ata_port *ap, u8 xfer_mode,
*/ */
static void ata_set_mode(struct ata_port *ap) static void ata_set_mode(struct ata_port *ap)
{ {
unsigned int i, xfer_shift; unsigned int xfer_shift;
u8 xfer_mode; u8 xfer_mode;
int rc; int rc;
...@@ -1670,11 +1644,6 @@ static void ata_set_mode(struct ata_port *ap) ...@@ -1670,11 +1644,6 @@ static void ata_set_mode(struct ata_port *ap)
if (ap->ops->post_set_mode) if (ap->ops->post_set_mode)
ap->ops->post_set_mode(ap); 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; return;
err_out: err_out:
......
...@@ -742,15 +742,10 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) ...@@ -742,15 +742,10 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd)
u32 n_block; u32 n_block;
tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
tf->protocol = qc->dev->xfer_protocol;
if (scsicmd[0] == READ_10 || scsicmd[0] == READ_6 || if (scsicmd[0] == WRITE_10 || scsicmd[0] == WRITE_6 ||
scsicmd[0] == READ_16) { scsicmd[0] == WRITE_16)
tf->command = qc->dev->read_cmd;
} else {
tf->command = qc->dev->write_cmd;
tf->flags |= ATA_TFLAG_WRITE; tf->flags |= ATA_TFLAG_WRITE;
}
/* Calculate the SCSI LBA and transfer length. */ /* Calculate the SCSI LBA and transfer length. */
switch (scsicmd[0]) { switch (scsicmd[0]) {
...@@ -812,6 +807,8 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) ...@@ -812,6 +807,8 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd)
tf->device |= (block >> 24) & 0xf; tf->device |= (block >> 24) & 0xf;
} }
ata_rwcmd_protocol(qc);
qc->nsect = n_block; qc->nsect = n_block;
tf->nsect = n_block & 0xff; tf->nsect = n_block & 0xff;
...@@ -828,6 +825,8 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) ...@@ -828,6 +825,8 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd)
if ((block >> 28) || (n_block > 256)) if ((block >> 28) || (n_block > 256))
goto out_of_range; goto out_of_range;
ata_rwcmd_protocol(qc);
/* Convert LBA to CHS */ /* Convert LBA to CHS */
track = (u32)block / dev->sectors; track = (u32)block / dev->sectors;
cyl = track / dev->heads; cyl = track / dev->heads;
......
...@@ -42,6 +42,7 @@ extern int atapi_enabled; ...@@ -42,6 +42,7 @@ extern int atapi_enabled;
extern int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat); extern int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat);
extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap, extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
struct ata_device *dev); struct ata_device *dev);
extern void ata_rwcmd_protocol(struct ata_queued_cmd *qc);
extern void ata_qc_free(struct ata_queued_cmd *qc); extern void ata_qc_free(struct ata_queued_cmd *qc);
extern int ata_qc_issue(struct ata_queued_cmd *qc); extern int ata_qc_issue(struct ata_queued_cmd *qc);
extern int ata_check_atapi_dma(struct ata_queued_cmd *qc); extern int ata_check_atapi_dma(struct ata_queued_cmd *qc);
......
...@@ -128,6 +128,10 @@ enum { ...@@ -128,6 +128,10 @@ enum {
ATA_CMD_PIO_READ_EXT = 0x24, ATA_CMD_PIO_READ_EXT = 0x24,
ATA_CMD_PIO_WRITE = 0x30, ATA_CMD_PIO_WRITE = 0x30,
ATA_CMD_PIO_WRITE_EXT = 0x34, ATA_CMD_PIO_WRITE_EXT = 0x34,
ATA_CMD_READ_MULTI = 0xC4,
ATA_CMD_READ_MULTI_EXT = 0x29,
ATA_CMD_WRITE_MULTI = 0xC5,
ATA_CMD_WRITE_MULTI_EXT = 0x39,
ATA_CMD_SET_FEATURES = 0xEF, ATA_CMD_SET_FEATURES = 0xEF,
ATA_CMD_PACKET = 0xA0, ATA_CMD_PACKET = 0xA0,
ATA_CMD_VERIFY = 0x40, ATA_CMD_VERIFY = 0x40,
......
...@@ -283,10 +283,8 @@ struct ata_device { ...@@ -283,10 +283,8 @@ struct ata_device {
u8 xfer_mode; u8 xfer_mode;
unsigned int xfer_shift; /* ATA_SHIFT_xxx */ unsigned int xfer_shift; /* ATA_SHIFT_xxx */
/* cache info about current transfer mode */ unsigned int multi_count; /* sectors count for
u8 xfer_protocol; /* taskfile xfer protocol */ READ/WRITE MULTIPLE */
u8 read_cmd; /* opcode to use on read */
u8 write_cmd; /* opcode to use on write */
/* for CHS addressing */ /* for CHS addressing */
u16 cylinders; /* Number of cylinders */ u16 cylinders; /* Number of cylinders */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment