forked from Minki/linux
scsi: sd: Improve sd_completed_bytes
Re-shuffle the code to be more efficient by not initializing variables upfront (i.e. do it only when necessary). Also replace the do_div calls with calls to sectors_to_logical(). No functional change is introduced by this patch. [mkp: bytes_to_logical()] Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
parent
7529fbb008
commit
6eadc61224
@ -1758,41 +1758,44 @@ static int sd_eh_action(struct scsi_cmnd *scmd, int eh_disp)
|
||||
|
||||
static unsigned int sd_completed_bytes(struct scsi_cmnd *scmd)
|
||||
{
|
||||
u64 start_lba = blk_rq_pos(scmd->request);
|
||||
u64 end_lba = blk_rq_pos(scmd->request) + (scsi_bufflen(scmd) / 512);
|
||||
u64 factor = scmd->device->sector_size / 512;
|
||||
u64 bad_lba;
|
||||
int info_valid;
|
||||
struct request *req = scmd->request;
|
||||
struct scsi_device *sdev = scmd->device;
|
||||
unsigned int transferred, good_bytes;
|
||||
u64 start_lba, end_lba, bad_lba;
|
||||
|
||||
/*
|
||||
* Some commands have a payload smaller than the device logical
|
||||
* block size (e.g. INQUIRY on a 4K disk).
|
||||
*/
|
||||
if (scsi_bufflen(scmd) <= sdev->sector_size)
|
||||
return 0;
|
||||
|
||||
/* Check if we have a 'bad_lba' information */
|
||||
if (!scsi_get_sense_info_fld(scmd->sense_buffer,
|
||||
SCSI_SENSE_BUFFERSIZE,
|
||||
&bad_lba))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If the bad lba was reported incorrectly, we have no idea where
|
||||
* the error is.
|
||||
*/
|
||||
start_lba = sectors_to_logical(sdev, blk_rq_pos(req));
|
||||
end_lba = start_lba + bytes_to_logical(sdev, scsi_bufflen(scmd));
|
||||
if (bad_lba < start_lba || bad_lba >= end_lba)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* resid is optional but mostly filled in. When it's unused,
|
||||
* its value is zero, so we assume the whole buffer transferred
|
||||
*/
|
||||
unsigned int transferred = scsi_bufflen(scmd) - scsi_get_resid(scmd);
|
||||
unsigned int good_bytes;
|
||||
transferred = scsi_bufflen(scmd) - scsi_get_resid(scmd);
|
||||
|
||||
info_valid = scsi_get_sense_info_fld(scmd->sense_buffer,
|
||||
SCSI_SENSE_BUFFERSIZE,
|
||||
&bad_lba);
|
||||
if (!info_valid)
|
||||
return 0;
|
||||
|
||||
if (scsi_bufflen(scmd) <= scmd->device->sector_size)
|
||||
return 0;
|
||||
|
||||
/* be careful ... don't want any overflows */
|
||||
do_div(start_lba, factor);
|
||||
do_div(end_lba, factor);
|
||||
|
||||
/* The bad lba was reported incorrectly, we have no idea where
|
||||
* the error is.
|
||||
/* This computation should always be done in terms of the
|
||||
* resolution of the device's medium.
|
||||
*/
|
||||
if (bad_lba < start_lba || bad_lba >= end_lba)
|
||||
return 0;
|
||||
good_bytes = logical_to_bytes(sdev, bad_lba - start_lba);
|
||||
|
||||
/* This computation should always be done in terms of
|
||||
* the resolution of the device's medium.
|
||||
*/
|
||||
good_bytes = (bad_lba - start_lba) * scmd->device->sector_size;
|
||||
return min(good_bytes, transferred);
|
||||
}
|
||||
|
||||
|
@ -169,6 +169,11 @@ static inline unsigned int logical_to_bytes(struct scsi_device *sdev, sector_t b
|
||||
return blocks * sdev->sector_size;
|
||||
}
|
||||
|
||||
static inline sector_t bytes_to_logical(struct scsi_device *sdev, unsigned int bytes)
|
||||
{
|
||||
return bytes >> ilog2(sdev->sector_size);
|
||||
}
|
||||
|
||||
static inline sector_t sectors_to_logical(struct scsi_device *sdev, sector_t sector)
|
||||
{
|
||||
return sector >> (ilog2(sdev->sector_size) - 9);
|
||||
|
Loading…
Reference in New Issue
Block a user