Commit 6a36261e authored by Tejun Heo's avatar Tejun Heo

[PATCH] libata: fix READ CAPACITY simulation

* READ CAPACITY (16) implementation fixed.  Result was shifted by two
  bytes.  Carlos Pardo spotted this problem and submitted preliminary
  patch.  Capacity => 2TB is handled correctly now.  (verifid w/ fake
  capacity)

* Use dev->n_sectors instead of re-reading directly from ID data.

* Define and use ATA_SCSI_RBUF_SET() which considers rbuf length.
  This should be done for all simulation functions.  Userland can
  issue any simulated command with arbitrary buffer length.
Signed-off-by: default avatarTejun Heo <htejun@gmail.com>
Cc: Carlos Pardo <Carlos.Pardo@siliconimage.com>
parent 3d3cca37
...@@ -1697,6 +1697,22 @@ void ata_scsi_rbuf_fill(struct ata_scsi_args *args, ...@@ -1697,6 +1697,22 @@ void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
args->done(cmd); args->done(cmd);
} }
/**
* ATA_SCSI_RBUF_SET - helper to set values in SCSI response buffer
* @idx: byte index into SCSI response buffer
* @val: value to set
*
* To be used by SCSI command simulator functions. This macros
* expects two local variables, u8 *rbuf and unsigned int buflen,
* are in scope.
*
* LOCKING:
* None.
*/
#define ATA_SCSI_RBUF_SET(idx, val) do { \
if ((idx) < buflen) rbuf[(idx)] = (u8)(val); \
} while (0)
/** /**
* ata_scsiop_inq_std - Simulate INQUIRY command * ata_scsiop_inq_std - Simulate INQUIRY command
* @args: device IDENTIFY data / SCSI command of interest. * @args: device IDENTIFY data / SCSI command of interest.
...@@ -2156,67 +2172,42 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, ...@@ -2156,67 +2172,42 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
* Simulate READ CAPACITY commands. * Simulate READ CAPACITY commands.
* *
* LOCKING: * LOCKING:
* spin_lock_irqsave(host lock) * None.
*/ */
unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf, unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
unsigned int buflen) unsigned int buflen)
{ {
u64 n_sectors; u64 last_lba = args->dev->n_sectors - 1; /* LBA of the last block */
u32 tmp;
VPRINTK("ENTER\n"); VPRINTK("ENTER\n");
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 */
if (args->cmd->cmnd[0] == READ_CAPACITY) { if (args->cmd->cmnd[0] == READ_CAPACITY) {
if( n_sectors >= 0xffffffffULL ) if (last_lba >= 0xffffffffULL)
tmp = 0xffffffff ; /* Return max count on overflow */ last_lba = 0xffffffff;
else
tmp = n_sectors ;
/* sector count, 32-bit */ /* sector count, 32-bit */
rbuf[0] = tmp >> (8 * 3); ATA_SCSI_RBUF_SET(0, last_lba >> (8 * 3));
rbuf[1] = tmp >> (8 * 2); ATA_SCSI_RBUF_SET(1, last_lba >> (8 * 2));
rbuf[2] = tmp >> (8 * 1); ATA_SCSI_RBUF_SET(2, last_lba >> (8 * 1));
rbuf[3] = tmp; ATA_SCSI_RBUF_SET(3, last_lba);
/* sector size */ /* sector size */
tmp = ATA_SECT_SIZE; ATA_SCSI_RBUF_SET(6, ATA_SECT_SIZE >> 8);
rbuf[6] = tmp >> 8; ATA_SCSI_RBUF_SET(7, ATA_SECT_SIZE);
rbuf[7] = tmp;
} else { } else {
/* sector count, 64-bit */ /* sector count, 64-bit */
tmp = n_sectors >> (8 * 4); ATA_SCSI_RBUF_SET(0, last_lba >> (8 * 7));
rbuf[2] = tmp >> (8 * 3); ATA_SCSI_RBUF_SET(1, last_lba >> (8 * 6));
rbuf[3] = tmp >> (8 * 2); ATA_SCSI_RBUF_SET(2, last_lba >> (8 * 5));
rbuf[4] = tmp >> (8 * 1); ATA_SCSI_RBUF_SET(3, last_lba >> (8 * 4));
rbuf[5] = tmp; ATA_SCSI_RBUF_SET(4, last_lba >> (8 * 3));
tmp = n_sectors; ATA_SCSI_RBUF_SET(5, last_lba >> (8 * 2));
rbuf[6] = tmp >> (8 * 3); ATA_SCSI_RBUF_SET(6, last_lba >> (8 * 1));
rbuf[7] = tmp >> (8 * 2); ATA_SCSI_RBUF_SET(7, last_lba);
rbuf[8] = tmp >> (8 * 1);
rbuf[9] = tmp;
/* sector size */ /* sector size */
tmp = ATA_SECT_SIZE; ATA_SCSI_RBUF_SET(10, ATA_SECT_SIZE >> 8);
rbuf[12] = tmp >> 8; ATA_SCSI_RBUF_SET(11, ATA_SECT_SIZE);
rbuf[13] = tmp;
} }
return 0; return 0;
......
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