[libata] C/H/S support, for older devices
This commit is contained in:
Родитель
88d7bd8cb9
Коммит
8bf62ecee5
|
@ -52,6 +52,7 @@
|
|||
static unsigned int ata_busy_sleep (struct ata_port *ap,
|
||||
unsigned long tmout_pat,
|
||||
unsigned long tmout);
|
||||
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);
|
||||
static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift);
|
||||
|
@ -1008,7 +1009,7 @@ static inline void ata_dump_id(struct ata_device *dev)
|
|||
static void ata_dev_identify(struct ata_port *ap, unsigned int device)
|
||||
{
|
||||
struct ata_device *dev = &ap->device[device];
|
||||
unsigned int i;
|
||||
unsigned int major_version;
|
||||
u16 tmp;
|
||||
unsigned long xfer_modes;
|
||||
u8 status;
|
||||
|
@ -1106,9 +1107,9 @@ retry:
|
|||
* common ATA, ATAPI feature tests
|
||||
*/
|
||||
|
||||
/* we require LBA and DMA support (bits 8 & 9 of word 49) */
|
||||
if (!ata_id_has_dma(dev->id) || !ata_id_has_lba(dev->id)) {
|
||||
printk(KERN_DEBUG "ata%u: no dma/lba\n", ap->id);
|
||||
/* we require DMA support (bits 8 of word 49) */
|
||||
if (!ata_id_has_dma(dev->id)) {
|
||||
printk(KERN_DEBUG "ata%u: no dma\n", ap->id);
|
||||
goto err_out_nosup;
|
||||
}
|
||||
|
||||
|
@ -1128,32 +1129,69 @@ retry:
|
|||
if (!ata_id_is_ata(dev->id)) /* sanity check */
|
||||
goto err_out_nosup;
|
||||
|
||||
/* get major version */
|
||||
tmp = dev->id[ATA_ID_MAJOR_VER];
|
||||
for (i = 14; i >= 1; i--)
|
||||
if (tmp & (1 << i))
|
||||
for (major_version = 14; major_version >= 1; major_version--)
|
||||
if (tmp & (1 << major_version))
|
||||
break;
|
||||
|
||||
/* we require at least ATA-3 */
|
||||
if (i < 3) {
|
||||
printk(KERN_DEBUG "ata%u: no ATA-3\n", ap->id);
|
||||
goto err_out_nosup;
|
||||
}
|
||||
/*
|
||||
* The exact sequence expected by certain pre-ATA4 drives is:
|
||||
* SRST RESET
|
||||
* IDENTIFY
|
||||
* INITIALIZE DEVICE PARAMETERS
|
||||
* anything else..
|
||||
* Some drives were very specific about that exact sequence.
|
||||
*/
|
||||
if (major_version < 4 || (!ata_id_has_lba(dev->id)))
|
||||
ata_dev_init_params(ap, dev);
|
||||
|
||||
if (ata_id_has_lba(dev->id)) {
|
||||
dev->flags |= ATA_DFLAG_LBA;
|
||||
|
||||
if (ata_id_has_lba48(dev->id)) {
|
||||
dev->flags |= ATA_DFLAG_LBA48;
|
||||
dev->n_sectors = ata_id_u64(dev->id, 100);
|
||||
} else {
|
||||
dev->n_sectors = ata_id_u32(dev->id, 60);
|
||||
}
|
||||
|
||||
/* print device info to dmesg */
|
||||
printk(KERN_INFO "ata%u: dev %u ATA-%d, max %s, %Lu sectors:%s\n",
|
||||
ap->id, device,
|
||||
major_version,
|
||||
ata_mode_string(xfer_modes),
|
||||
(unsigned long long)dev->n_sectors,
|
||||
dev->flags & ATA_DFLAG_LBA48 ? " LBA48" : " LBA");
|
||||
} else {
|
||||
/* CHS */
|
||||
|
||||
/* Default translation */
|
||||
dev->cylinders = dev->id[1];
|
||||
dev->heads = dev->id[3];
|
||||
dev->sectors = dev->id[6];
|
||||
dev->n_sectors = dev->cylinders * dev->heads * dev->sectors;
|
||||
|
||||
if (ata_id_current_chs_valid(dev->id)) {
|
||||
/* Current CHS translation is valid. */
|
||||
dev->cylinders = dev->id[54];
|
||||
dev->heads = dev->id[55];
|
||||
dev->sectors = dev->id[56];
|
||||
|
||||
dev->n_sectors = ata_id_u32(dev->id, 57);
|
||||
}
|
||||
|
||||
/* print device info to dmesg */
|
||||
printk(KERN_INFO "ata%u: dev %u ATA-%d, max %s, %Lu sectors: CHS %d/%d/%d\n",
|
||||
ap->id, device,
|
||||
major_version,
|
||||
ata_mode_string(xfer_modes),
|
||||
(unsigned long long)dev->n_sectors,
|
||||
(int)dev->cylinders, (int)dev->heads, (int)dev->sectors);
|
||||
|
||||
if (ata_id_has_lba48(dev->id)) {
|
||||
dev->flags |= ATA_DFLAG_LBA48;
|
||||
dev->n_sectors = ata_id_u64(dev->id, 100);
|
||||
} else {
|
||||
dev->n_sectors = ata_id_u32(dev->id, 60);
|
||||
}
|
||||
|
||||
ap->host->max_cmd_len = 16;
|
||||
|
||||
/* print device info to dmesg */
|
||||
printk(KERN_INFO "ata%u: dev %u ATA, max %s, %Lu sectors:%s\n",
|
||||
ap->id, device,
|
||||
ata_mode_string(xfer_modes),
|
||||
(unsigned long long)dev->n_sectors,
|
||||
dev->flags & ATA_DFLAG_LBA48 ? " lba48" : "");
|
||||
}
|
||||
|
||||
/* ATAPI-specific feature tests */
|
||||
|
@ -1946,6 +1984,54 @@ static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev)
|
|||
DPRINTK("EXIT\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_dev_init_params - Issue INIT DEV PARAMS command
|
||||
* @ap: Port associated with device @dev
|
||||
* @dev: Device to which command will be sent
|
||||
*
|
||||
* LOCKING:
|
||||
*/
|
||||
|
||||
static void ata_dev_init_params(struct ata_port *ap, struct ata_device *dev)
|
||||
{
|
||||
DECLARE_COMPLETION(wait);
|
||||
struct ata_queued_cmd *qc;
|
||||
int rc;
|
||||
unsigned long flags;
|
||||
u16 sectors = dev->id[6];
|
||||
u16 heads = dev->id[3];
|
||||
|
||||
/* Number of sectors per track 1-255. Number of heads 1-16 */
|
||||
if (sectors < 1 || sectors > 255 || heads < 1 || heads > 16)
|
||||
return;
|
||||
|
||||
/* set up init dev params taskfile */
|
||||
DPRINTK("init dev params \n");
|
||||
|
||||
qc = ata_qc_new_init(ap, dev);
|
||||
BUG_ON(qc == NULL);
|
||||
|
||||
qc->tf.command = ATA_CMD_INIT_DEV_PARAMS;
|
||||
qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
|
||||
qc->tf.protocol = ATA_PROT_NODATA;
|
||||
qc->tf.nsect = sectors;
|
||||
qc->tf.device |= (heads - 1) & 0x0f; /* max head = num. of heads - 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)
|
||||
ata_port_disable(ap);
|
||||
else
|
||||
wait_for_completion(&wait);
|
||||
|
||||
DPRINTK("EXIT\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_sg_clean -
|
||||
* @qc:
|
||||
|
@ -2736,8 +2822,12 @@ struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
|
|||
|
||||
ata_tf_init(ap, &qc->tf, dev->devno);
|
||||
|
||||
if (dev->flags & ATA_DFLAG_LBA48)
|
||||
qc->tf.flags |= ATA_TFLAG_LBA48;
|
||||
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;
|
||||
|
|
|
@ -435,78 +435,108 @@ static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, u8 *scsicmd)
|
|||
static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd)
|
||||
{
|
||||
struct ata_taskfile *tf = &qc->tf;
|
||||
struct ata_device *dev = qc->dev;
|
||||
unsigned int lba = tf->flags & ATA_TFLAG_LBA;
|
||||
unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48;
|
||||
u64 dev_sectors = qc->dev->n_sectors;
|
||||
u64 sect = 0;
|
||||
u32 n_sect = 0;
|
||||
u64 block = 0;
|
||||
u32 n_block = 0;
|
||||
|
||||
tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
|
||||
tf->protocol = ATA_PROT_NODATA;
|
||||
tf->device |= ATA_LBA;
|
||||
|
||||
if (scsicmd[0] == VERIFY) {
|
||||
sect |= ((u64)scsicmd[2]) << 24;
|
||||
sect |= ((u64)scsicmd[3]) << 16;
|
||||
sect |= ((u64)scsicmd[4]) << 8;
|
||||
sect |= ((u64)scsicmd[5]);
|
||||
block |= ((u64)scsicmd[2]) << 24;
|
||||
block |= ((u64)scsicmd[3]) << 16;
|
||||
block |= ((u64)scsicmd[4]) << 8;
|
||||
block |= ((u64)scsicmd[5]);
|
||||
|
||||
n_sect |= ((u32)scsicmd[7]) << 8;
|
||||
n_sect |= ((u32)scsicmd[8]);
|
||||
n_block |= ((u32)scsicmd[7]) << 8;
|
||||
n_block |= ((u32)scsicmd[8]);
|
||||
}
|
||||
|
||||
else if (scsicmd[0] == VERIFY_16) {
|
||||
sect |= ((u64)scsicmd[2]) << 56;
|
||||
sect |= ((u64)scsicmd[3]) << 48;
|
||||
sect |= ((u64)scsicmd[4]) << 40;
|
||||
sect |= ((u64)scsicmd[5]) << 32;
|
||||
sect |= ((u64)scsicmd[6]) << 24;
|
||||
sect |= ((u64)scsicmd[7]) << 16;
|
||||
sect |= ((u64)scsicmd[8]) << 8;
|
||||
sect |= ((u64)scsicmd[9]);
|
||||
block |= ((u64)scsicmd[2]) << 56;
|
||||
block |= ((u64)scsicmd[3]) << 48;
|
||||
block |= ((u64)scsicmd[4]) << 40;
|
||||
block |= ((u64)scsicmd[5]) << 32;
|
||||
block |= ((u64)scsicmd[6]) << 24;
|
||||
block |= ((u64)scsicmd[7]) << 16;
|
||||
block |= ((u64)scsicmd[8]) << 8;
|
||||
block |= ((u64)scsicmd[9]);
|
||||
|
||||
n_sect |= ((u32)scsicmd[10]) << 24;
|
||||
n_sect |= ((u32)scsicmd[11]) << 16;
|
||||
n_sect |= ((u32)scsicmd[12]) << 8;
|
||||
n_sect |= ((u32)scsicmd[13]);
|
||||
n_block |= ((u32)scsicmd[10]) << 24;
|
||||
n_block |= ((u32)scsicmd[11]) << 16;
|
||||
n_block |= ((u32)scsicmd[12]) << 8;
|
||||
n_block |= ((u32)scsicmd[13]);
|
||||
}
|
||||
|
||||
else
|
||||
return 1;
|
||||
|
||||
if (!n_sect)
|
||||
if (!n_block)
|
||||
return 1;
|
||||
if (sect >= dev_sectors)
|
||||
if (block >= dev_sectors)
|
||||
return 1;
|
||||
if ((sect + n_sect) > dev_sectors)
|
||||
if ((block + n_block) > dev_sectors)
|
||||
return 1;
|
||||
if (lba48) {
|
||||
if (n_sect > (64 * 1024))
|
||||
if (n_block > (64 * 1024))
|
||||
return 1;
|
||||
} else {
|
||||
if (n_sect > 256)
|
||||
if (n_block > 256)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (lba48) {
|
||||
tf->command = ATA_CMD_VERIFY_EXT;
|
||||
if (lba) {
|
||||
if (lba48) {
|
||||
tf->command = ATA_CMD_VERIFY_EXT;
|
||||
|
||||
tf->hob_nsect = (n_sect >> 8) & 0xff;
|
||||
tf->hob_nsect = (n_block >> 8) & 0xff;
|
||||
|
||||
tf->hob_lbah = (sect >> 40) & 0xff;
|
||||
tf->hob_lbam = (sect >> 32) & 0xff;
|
||||
tf->hob_lbal = (sect >> 24) & 0xff;
|
||||
tf->hob_lbah = (block >> 40) & 0xff;
|
||||
tf->hob_lbam = (block >> 32) & 0xff;
|
||||
tf->hob_lbal = (block >> 24) & 0xff;
|
||||
} else {
|
||||
tf->command = ATA_CMD_VERIFY;
|
||||
|
||||
tf->device |= (block >> 24) & 0xf;
|
||||
}
|
||||
|
||||
tf->nsect = n_block & 0xff;
|
||||
|
||||
tf->lbah = (block >> 16) & 0xff;
|
||||
tf->lbam = (block >> 8) & 0xff;
|
||||
tf->lbal = block & 0xff;
|
||||
|
||||
tf->device |= ATA_LBA;
|
||||
} else {
|
||||
/* CHS */
|
||||
u32 sect, head, cyl, track;
|
||||
|
||||
/* Convert LBA to CHS */
|
||||
track = (u32)block / dev->sectors;
|
||||
cyl = track / dev->heads;
|
||||
head = track % dev->heads;
|
||||
sect = (u32)block % dev->sectors + 1;
|
||||
|
||||
DPRINTK("block[%u] track[%u] cyl[%u] head[%u] sect[%u] \n", (u32)block, track, cyl, head, sect);
|
||||
|
||||
/* Check whether the converted CHS can fit.
|
||||
Cylinder: 0-65535
|
||||
Head: 0-15
|
||||
Sector: 1-255*/
|
||||
if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect))
|
||||
return 1;
|
||||
|
||||
tf->command = ATA_CMD_VERIFY;
|
||||
|
||||
tf->device |= (sect >> 24) & 0xf;
|
||||
tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */
|
||||
tf->lbal = sect;
|
||||
tf->lbam = cyl;
|
||||
tf->lbah = cyl >> 8;
|
||||
tf->device |= head;
|
||||
}
|
||||
|
||||
tf->nsect = n_sect & 0xff;
|
||||
|
||||
tf->lbah = (sect >> 16) & 0xff;
|
||||
tf->lbam = (sect >> 8) & 0xff;
|
||||
tf->lbal = sect & 0xff;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -533,11 +563,14 @@ static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd)
|
|||
static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd)
|
||||
{
|
||||
struct ata_taskfile *tf = &qc->tf;
|
||||
struct ata_device *dev = qc->dev;
|
||||
unsigned int lba = tf->flags & ATA_TFLAG_LBA;
|
||||
unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48;
|
||||
u64 block = 0;
|
||||
u32 n_block = 0;
|
||||
|
||||
tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
|
||||
tf->protocol = qc->dev->xfer_protocol;
|
||||
tf->device |= ATA_LBA;
|
||||
|
||||
if (scsicmd[0] == READ_10 || scsicmd[0] == READ_6 ||
|
||||
scsicmd[0] == READ_16) {
|
||||
|
@ -547,80 +580,111 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd)
|
|||
tf->flags |= ATA_TFLAG_WRITE;
|
||||
}
|
||||
|
||||
/* Calculate the SCSI LBA and transfer length. */
|
||||
if (scsicmd[0] == READ_10 || scsicmd[0] == WRITE_10) {
|
||||
if (lba48) {
|
||||
tf->hob_nsect = scsicmd[7];
|
||||
tf->hob_lbal = scsicmd[2];
|
||||
block |= ((u64)scsicmd[2]) << 24;
|
||||
block |= ((u64)scsicmd[3]) << 16;
|
||||
block |= ((u64)scsicmd[4]) << 8;
|
||||
block |= ((u64)scsicmd[5]);
|
||||
|
||||
qc->nsect = ((unsigned int)scsicmd[7] << 8) |
|
||||
scsicmd[8];
|
||||
} else {
|
||||
/* if we don't support LBA48 addressing, the request
|
||||
* -may- be too large. */
|
||||
if ((scsicmd[2] & 0xf0) || scsicmd[7])
|
||||
return 1;
|
||||
|
||||
/* stores LBA27:24 in lower 4 bits of device reg */
|
||||
tf->device |= scsicmd[2];
|
||||
|
||||
qc->nsect = scsicmd[8];
|
||||
}
|
||||
|
||||
tf->nsect = scsicmd[8];
|
||||
tf->lbal = scsicmd[5];
|
||||
tf->lbam = scsicmd[4];
|
||||
tf->lbah = scsicmd[3];
|
||||
n_block |= ((u32)scsicmd[7]) << 8;
|
||||
n_block |= ((u32)scsicmd[8]);
|
||||
|
||||
VPRINTK("ten-byte command\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (scsicmd[0] == READ_6 || scsicmd[0] == WRITE_6) {
|
||||
qc->nsect = tf->nsect = scsicmd[4];
|
||||
tf->lbal = scsicmd[3];
|
||||
tf->lbam = scsicmd[2];
|
||||
tf->lbah = scsicmd[1] & 0x1f; /* mask out reserved bits */
|
||||
|
||||
} else if (scsicmd[0] == READ_6 || scsicmd[0] == WRITE_6) {
|
||||
block |= ((u64)scsicmd[2]) << 8;
|
||||
block |= ((u64)scsicmd[3]);
|
||||
n_block |= ((u32)scsicmd[4]);
|
||||
|
||||
VPRINTK("six-byte command\n");
|
||||
return 0;
|
||||
}
|
||||
} else if (scsicmd[0] == READ_16 || scsicmd[0] == WRITE_16) {
|
||||
block |= ((u64)scsicmd[2]) << 56;
|
||||
block |= ((u64)scsicmd[3]) << 48;
|
||||
block |= ((u64)scsicmd[4]) << 40;
|
||||
block |= ((u64)scsicmd[5]) << 32;
|
||||
block |= ((u64)scsicmd[6]) << 24;
|
||||
block |= ((u64)scsicmd[7]) << 16;
|
||||
block |= ((u64)scsicmd[8]) << 8;
|
||||
block |= ((u64)scsicmd[9]);
|
||||
|
||||
if (scsicmd[0] == READ_16 || scsicmd[0] == WRITE_16) {
|
||||
/* rule out impossible LBAs and sector counts */
|
||||
if (scsicmd[2] || scsicmd[3] || scsicmd[10] || scsicmd[11])
|
||||
return 1;
|
||||
|
||||
if (lba48) {
|
||||
tf->hob_nsect = scsicmd[12];
|
||||
tf->hob_lbal = scsicmd[6];
|
||||
tf->hob_lbam = scsicmd[5];
|
||||
tf->hob_lbah = scsicmd[4];
|
||||
|
||||
qc->nsect = ((unsigned int)scsicmd[12] << 8) |
|
||||
scsicmd[13];
|
||||
} else {
|
||||
/* once again, filter out impossible non-zero values */
|
||||
if (scsicmd[4] || scsicmd[5] || scsicmd[12] ||
|
||||
(scsicmd[6] & 0xf0))
|
||||
return 1;
|
||||
|
||||
/* stores LBA27:24 in lower 4 bits of device reg */
|
||||
tf->device |= scsicmd[6];
|
||||
|
||||
qc->nsect = scsicmd[13];
|
||||
}
|
||||
|
||||
tf->nsect = scsicmd[13];
|
||||
tf->lbal = scsicmd[9];
|
||||
tf->lbam = scsicmd[8];
|
||||
tf->lbah = scsicmd[7];
|
||||
n_block |= ((u32)scsicmd[10]) << 24;
|
||||
n_block |= ((u32)scsicmd[11]) << 16;
|
||||
n_block |= ((u32)scsicmd[12]) << 8;
|
||||
n_block |= ((u32)scsicmd[13]);
|
||||
|
||||
VPRINTK("sixteen-byte command\n");
|
||||
return 0;
|
||||
} else {
|
||||
DPRINTK("no-byte command\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
DPRINTK("no-byte command\n");
|
||||
return 1;
|
||||
/* Check and compose ATA command */
|
||||
if (!n_block)
|
||||
/* In ATA, sector count 0 means 256 or 65536 sectors, not 0 sectors. */
|
||||
return 1;
|
||||
|
||||
if (lba) {
|
||||
if (lba48) {
|
||||
/* The request -may- be too large for LBA48. */
|
||||
if ((block >> 48) || (n_block > 65536))
|
||||
return 1;
|
||||
|
||||
tf->hob_nsect = (n_block >> 8) & 0xff;
|
||||
|
||||
tf->hob_lbah = (block >> 40) & 0xff;
|
||||
tf->hob_lbam = (block >> 32) & 0xff;
|
||||
tf->hob_lbal = (block >> 24) & 0xff;
|
||||
} else {
|
||||
/* LBA28 */
|
||||
|
||||
/* The request -may- be too large for LBA28. */
|
||||
if ((block >> 28) || (n_block > 256))
|
||||
return 1;
|
||||
|
||||
tf->device |= (block >> 24) & 0xf;
|
||||
}
|
||||
|
||||
qc->nsect = n_block;
|
||||
tf->nsect = n_block & 0xff;
|
||||
|
||||
tf->lbah = (block >> 16) & 0xff;
|
||||
tf->lbam = (block >> 8) & 0xff;
|
||||
tf->lbal = block & 0xff;
|
||||
|
||||
tf->device |= ATA_LBA;
|
||||
} else {
|
||||
/* CHS */
|
||||
u32 sect, head, cyl, track;
|
||||
|
||||
/* The request -may- be too large for CHS addressing. */
|
||||
if ((block >> 28) || (n_block > 256))
|
||||
return 1;
|
||||
|
||||
/* Convert LBA to CHS */
|
||||
track = (u32)block / dev->sectors;
|
||||
cyl = track / dev->heads;
|
||||
head = track % dev->heads;
|
||||
sect = (u32)block % dev->sectors + 1;
|
||||
|
||||
DPRINTK("block[%u] track[%u] cyl[%u] head[%u] sect[%u] \n",
|
||||
(u32)block, track, cyl, head, sect);
|
||||
|
||||
/* Check whether the converted CHS can fit.
|
||||
Cylinder: 0-65535
|
||||
Head: 0-15
|
||||
Sector: 1-255*/
|
||||
if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect))
|
||||
return 1;
|
||||
|
||||
qc->nsect = n_block;
|
||||
tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */
|
||||
tf->lbal = sect;
|
||||
tf->lbam = cyl;
|
||||
tf->lbah = cyl >> 8;
|
||||
tf->device |= head;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ata_scsi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
|
||||
|
@ -1167,10 +1231,20 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
|
|||
|
||||
VPRINTK("ENTER\n");
|
||||
|
||||
if (ata_id_has_lba48(args->id))
|
||||
n_sectors = ata_id_u64(args->id, 100);
|
||||
else
|
||||
n_sectors = ata_id_u32(args->id, 60);
|
||||
if (ata_id_has_lba(args->id)) {
|
||||
if (ata_id_has_lba48(args->id))
|
||||
n_sectors = ata_id_u64(args->id, 100);
|
||||
else
|
||||
n_sectors = ata_id_u32(args->id, 60);
|
||||
} else {
|
||||
/* CHS default translation */
|
||||
n_sectors = args->id[1] * args->id[3] * args->id[6];
|
||||
|
||||
if (ata_id_current_chs_valid(args->id))
|
||||
/* CHS current translation */
|
||||
n_sectors = ata_id_u32(args->id, 57);
|
||||
}
|
||||
|
||||
n_sectors--; /* ATA TotalUserSectors - 1 */
|
||||
|
||||
tmp = n_sectors; /* note: truncates, if lba48 */
|
||||
|
|
|
@ -125,6 +125,7 @@ enum {
|
|||
ATA_CMD_PACKET = 0xA0,
|
||||
ATA_CMD_VERIFY = 0x40,
|
||||
ATA_CMD_VERIFY_EXT = 0x42,
|
||||
ATA_CMD_INIT_DEV_PARAMS = 0x91,
|
||||
|
||||
/* SETFEATURES stuff */
|
||||
SETFEATURES_XFER = 0x03,
|
||||
|
@ -174,6 +175,7 @@ enum {
|
|||
ATA_TFLAG_ISADDR = (1 << 1), /* enable r/w to nsect/lba regs */
|
||||
ATA_TFLAG_DEVICE = (1 << 2), /* enable r/w to device reg */
|
||||
ATA_TFLAG_WRITE = (1 << 3), /* data dir: host->dev==1 (write) */
|
||||
ATA_TFLAG_LBA = (1 << 4), /* enable LBA */
|
||||
};
|
||||
|
||||
enum ata_tf_protocols {
|
||||
|
@ -242,6 +244,18 @@ struct ata_taskfile {
|
|||
((u64) (id)[(n) + 1] << 16) | \
|
||||
((u64) (id)[(n) + 0]) )
|
||||
|
||||
static inline int ata_id_current_chs_valid(u16 *id)
|
||||
{
|
||||
/* For ATA-1 devices, if the INITIALIZE DEVICE PARAMETERS command
|
||||
has not been issued to the device then the values of
|
||||
id[54] to id[56] are vendor specific. */
|
||||
return (id[53] & 0x01) && /* Current translation valid */
|
||||
id[54] && /* cylinders in current translation */
|
||||
id[55] && /* heads in current translation */
|
||||
id[55] <= 16 &&
|
||||
id[56]; /* sectors in current translation */
|
||||
}
|
||||
|
||||
static inline int atapi_cdb_len(u16 *dev_id)
|
||||
{
|
||||
u16 tmp = dev_id[0] & 0x3;
|
||||
|
|
|
@ -95,6 +95,7 @@ enum {
|
|||
ATA_DFLAG_LBA48 = (1 << 0), /* device supports LBA48 */
|
||||
ATA_DFLAG_PIO = (1 << 1), /* device currently in PIO mode */
|
||||
ATA_DFLAG_LOCK_SECTORS = (1 << 2), /* don't adjust max_sectors */
|
||||
ATA_DFLAG_LBA = (1 << 3), /* device supports LBA */
|
||||
|
||||
ATA_DEV_UNKNOWN = 0, /* unknown device */
|
||||
ATA_DEV_ATA = 1, /* ATA device */
|
||||
|
@ -278,6 +279,11 @@ struct ata_device {
|
|||
u8 xfer_protocol; /* taskfile xfer protocol */
|
||||
u8 read_cmd; /* opcode to use on read */
|
||||
u8 write_cmd; /* opcode to use on write */
|
||||
|
||||
/* for CHS addressing */
|
||||
u16 cylinders; /* Number of cylinders */
|
||||
u16 heads; /* Number of heads */
|
||||
u16 sectors; /* Number of sectors per track */
|
||||
};
|
||||
|
||||
struct ata_port {
|
||||
|
|
Загрузка…
Ссылка в новой задаче