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)
|
static unsigned int sd_completed_bytes(struct scsi_cmnd *scmd)
|
||||||
{
|
{
|
||||||
u64 start_lba = blk_rq_pos(scmd->request);
|
struct request *req = scmd->request;
|
||||||
u64 end_lba = blk_rq_pos(scmd->request) + (scsi_bufflen(scmd) / 512);
|
struct scsi_device *sdev = scmd->device;
|
||||||
u64 factor = scmd->device->sector_size / 512;
|
unsigned int transferred, good_bytes;
|
||||||
u64 bad_lba;
|
u64 start_lba, end_lba, bad_lba;
|
||||||
int info_valid;
|
|
||||||
|
/*
|
||||||
|
* 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,
|
* resid is optional but mostly filled in. When it's unused,
|
||||||
* its value is zero, so we assume the whole buffer transferred
|
* its value is zero, so we assume the whole buffer transferred
|
||||||
*/
|
*/
|
||||||
unsigned int transferred = scsi_bufflen(scmd) - scsi_get_resid(scmd);
|
transferred = scsi_bufflen(scmd) - scsi_get_resid(scmd);
|
||||||
unsigned int good_bytes;
|
|
||||||
|
|
||||||
info_valid = scsi_get_sense_info_fld(scmd->sense_buffer,
|
/* This computation should always be done in terms of the
|
||||||
SCSI_SENSE_BUFFERSIZE,
|
* resolution of the device's medium.
|
||||||
&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.
|
|
||||||
*/
|
*/
|
||||||
if (bad_lba < start_lba || bad_lba >= end_lba)
|
good_bytes = logical_to_bytes(sdev, bad_lba - start_lba);
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* 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);
|
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;
|
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)
|
static inline sector_t sectors_to_logical(struct scsi_device *sdev, sector_t sector)
|
||||||
{
|
{
|
||||||
return sector >> (ilog2(sdev->sector_size) - 9);
|
return sector >> (ilog2(sdev->sector_size) - 9);
|
||||||
|
Loading…
Reference in New Issue
Block a user