Cleanup and improve libata-scsi command emulation
Damien Le Moal
maintainercover Cleanup and improve libata-scsi command emulation
The first 5 patches of this series refactor and cleanup the libata-scsi code handling command emulation. There are no functional changes introduced by these patches.
The last patch of the series (patch 6) improves the command emulation by accurately handling the scsi command residual and transferring back to the requester only the relevant data of a command reply.
Damien Le Moal (6):
ata: libata-scsi: Refactor ata_scsi_simulate()
ata: libata-scsi: Refactor ata_scsiop_read_cap()
ata: libata-scsi: Refactor ata_scsiop_maint_in()
ata: libata-scsi: Document all VPD page inquiry actors
ata: libata-scsi: Remove struct ata_scsi_args
ata: libata-scsi: Return residual for emulated SCSI commands
drivers/ata/libata-scsi.c | 503 +++++++++++++++++++++++--------------- 1 file changed, 305 insertions(+), 198 deletions(-)
Signature · 1 line
2.47.0
Damien Le Moal
maintainerPATCH 1/6 ata: libata-scsi: Refactor ata_scsi_simulate()
Factor out the code handling the INQUIRY command in ata_scsi_simulate() using the function ata_scsi_rbuf_fill() with the new actor ata_scsiop_inquiry(). This new actor function calls the existing actors to handle the standard inquiry as well as extended inquiry (VPD page access).
--- drivers/ata/libata-scsi.c | 106 ++++++++++++++++++++++---------------- 1 file changed, 63 insertions(+), 43 deletions(-)
drivers/ata/libata-scsi.c +63 -43
@@ -1815,7 +1815,7 @@ static void ata_scsi_rbuf_fill(struct ata_scsi_args *args, }/** -* ata_scsiop_inq_std - Simulate INQUIRY command +* ata_scsiop_inq_std - Simulate standard INQUIRY command * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. *
@@ -2121,6 +2121,11 @@ static unsigned int ata_scsiop_inq_b2(struct ata_scsi_args *args, u8 *rbuf)static unsigned int ata_scsiop_inq_b6 (struct ata_scsi_args *args,u8 *rbuf) { +if (!(args->dev->flags &ATA_DFLAG_ZAC )) { +ata_scsi_set_invalid_field (args->dev, args->cmd,2 ,0xff ); +return 1 ; + } +/* * zbc-r05 SCSI Zoned Block device characteristics VPD page */
@@ -2145,6 +2150,11 @@ static unsigned int ata_scsiop_inq_b9(struct ata_scsi_args *args, u8 *rbuf)u8 *desc = &rbuf[64 ];int i; +if (!cpr_log) { +ata_scsi_set_invalid_field (args->dev, args->cmd,2 ,0xff ); +return 1 ; + } +/* SCSI Concurrent Positioning Ranges VPD page: SBC-5 rev 1 or later */ rbuf[1 ] =0xb9 ;put_unaligned_be16 (64 + (int )cpr_log->nr_cpr *32 -4 , &rbuf[2 ]);
@@ -2159,6 +2169,57 @@ static unsigned int ata_scsiop_inq_b9(struct ata_scsi_args *args, u8 *rbuf)return 0 ; } +/** +* ata_scsiop_inquiry - Simulate INQUIRY command +* @args: device IDENTIFY data / SCSI command of interest. +* @rbuf: Response buffer, to which simulated SCSI cmd output is sent. +* +* Returns data associated with an INQUIRY command output. +* +* LOCKING: +* spin_lock_irqsave(host lock) +*/ +static unsigned int ata_scsiop_inquiry (struct ata_scsi_args *args,u8 *rbuf) +{ +struct ata_device *dev = args->dev; +struct scsi_cmnd *cmd = args->cmd; +const u8 *scsicmd = cmd->cmnd; + +/* is CmdDt set? */ +if (scsicmd[1 ] &2 ) { +ata_scsi_set_invalid_field (dev, cmd,1 ,0xff ); +return 1 ; + } + +/* Is EVPD clear? */ +if ((scsicmd[1 ] &1 ) ==0 ) +return ata_scsiop_inq_std (args, rbuf); + +switch (scsicmd[2 ]) { +case 0x00 : +return ata_scsiop_inq_00 (args, rbuf); +case 0x80 : +return ata_scsiop_inq_80 (args, rbuf); +case 0x83 : +return ata_scsiop_inq_83 (args, rbuf); +case 0x89 : +return ata_scsiop_inq_89 (args, rbuf); +case 0xb0 : +return ata_scsiop_inq_b0 (args, rbuf); +case 0xb1 : +return ata_scsiop_inq_b1 (args, rbuf); +case 0xb2 : +return ata_scsiop_inq_b2 (args, rbuf); +case 0xb6 : +return ata_scsiop_inq_b6 (args, rbuf); +case 0xb9 : +return ata_scsiop_inq_b9 (args, rbuf); +default : +ata_scsi_set_invalid_field (dev, cmd,2 ,0xff ); +return 1 ; + } +} +/** * modecpy - Prepare response for MODE SENSE * @dest: output buffer
@@ -4263,48 +4324,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd)switch (scsicmd[0 ]) {case INQUIRY : -if (scsicmd[1 ] &2 )/* is CmdDt set? */ -ata_scsi_set_invalid_field (dev, cmd,1 ,0xff ); -else if ((scsicmd[1 ] &1 ) ==0 )/* is EVPD clear? */ -ata_scsi_rbuf_fill (&args, ata_scsiop_inq_std); -else switch (scsicmd[2 ]) { -case 0x00 : -ata_scsi_rbuf_fill (&args, ata_scsiop_inq_00); -break ; -case 0x80 : -ata_scsi_rbuf_fill (&args, ata_scsiop_inq_80); -break ; -case 0x83 : -ata_scsi_rbuf_fill (&args, ata_scsiop_inq_83); -break ; -case 0x89 : -ata_scsi_rbuf_fill (&args, ata_scsiop_inq_89); -break ; -case 0xb0 : -ata_scsi_rbuf_fill (&args, ata_scsiop_inq_b0); -break ; -case 0xb1 : -ata_scsi_rbuf_fill (&args, ata_scsiop_inq_b1); -break ; -case 0xb2 : -ata_scsi_rbuf_fill (&args, ata_scsiop_inq_b2); -break ; -case 0xb6 : -if (dev->flags &ATA_DFLAG_ZAC ) -ata_scsi_rbuf_fill (&args, ata_scsiop_inq_b6); -else -ata_scsi_set_invalid_field (dev, cmd,2 ,0xff ); -break ; -case 0xb9 : -if (dev->cpr_log) -ata_scsi_rbuf_fill (&args, ata_scsiop_inq_b9); -else -ata_scsi_set_invalid_field (dev, cmd,2 ,0xff ); -break ; -default : -ata_scsi_set_invalid_field (dev, cmd,2 ,0xff ); -break ; - } +ata_scsi_rbuf_fill (&args, ata_scsiop_inquiry);break ;case MODE_SENSE :
Signature · 1 line
2.47.0
Damien Le Moal
maintainerPATCH 2/6 ata: libata-scsi: Refactor ata_scsiop_read_cap()
In reply to Damien Le MoalMove the check for the scsi command service action being SAI_READ_CAPACITY_16 from ata_scsi_simulate() into ata_scsiop_read_cap() to simplify ata_scsi_simulate() for processing capacity reading commands (READ_CAPACITY and SERVICE_ACTION_IN_16).
--- drivers/ata/libata-scsi.c | 87 +++++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 41 deletions(-)
drivers/ata/libata-scsi.c +46 -41
@@ -2579,6 +2579,7 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf)static unsigned int ata_scsiop_read_cap (struct ata_scsi_args *args,u8 *rbuf) {struct ata_device *dev = args->dev; +u8 *scsicmd = args->cmd->cmnd;u64 last_lba = dev->n_sectors -1 ;/* LBA of the last block */ u32 sector_size;/* physical sector size in bytes */ u8 log2_per_phys;
@@ -2588,7 +2589,7 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf) log2_per_phys =ata_id_log2_per_physical_sector (dev->id); lowest_aligned =ata_id_logical_sector_offset (dev->id, log2_per_phys); -if (args->cmd->cmnd[0 ] ==READ_CAPACITY ) { +if (scsicmd[0 ] ==READ_CAPACITY ) {if (last_lba >=0xffffffffULL ) last_lba =0xffffffff ;
@@ -2603,42 +2604,52 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf) rbuf[5 ] = sector_size >> (8 *2 ); rbuf[6 ] = sector_size >> (8 *1 ); rbuf[7 ] = sector_size; - }else { -/* sector count, 64-bit */ - rbuf[0 ] = last_lba >> (8 *7 ); - rbuf[1 ] = last_lba >> (8 *6 ); - rbuf[2 ] = last_lba >> (8 *5 ); - rbuf[3 ] = last_lba >> (8 *4 ); - rbuf[4 ] = last_lba >> (8 *3 ); - rbuf[5 ] = last_lba >> (8 *2 ); - rbuf[6 ] = last_lba >> (8 *1 ); - rbuf[7 ] = last_lba; -/* sector size */ - rbuf[8 ] = sector_size >> (8 *3 ); - rbuf[9 ] = sector_size >> (8 *2 ); - rbuf[10 ] = sector_size >> (8 *1 ); - rbuf[11 ] = sector_size; - - rbuf[12 ] =0 ; - rbuf[13 ] = log2_per_phys; - rbuf[14 ] = (lowest_aligned >>8 ) &0x3f ; - rbuf[15 ] = lowest_aligned; - -if (ata_id_has_trim (args->id) && - !(dev->quirks &ATA_QUIRK_NOTRIM )) { - rbuf[14 ] |=0x80 ;/* LBPME */ - -if (ata_id_has_zero_after_trim (args->id) && - dev->quirks &ATA_QUIRK_ZERO_AFTER_TRIM ) { -ata_dev_info (dev,"Enabling discard_zeroes_data\n" ); - rbuf[14 ] |=0x40 ;/* LBPRZ */ - } +return 0 ; + } + +/* +* READ CAPACITY 16 command is defined as a service action +* (SERVICE_ACTION_IN_16 command). +*/ +if (scsicmd[0 ] !=SERVICE_ACTION_IN_16 || + (scsicmd[1 ] &0x1f ) !=SAI_READ_CAPACITY_16 ) { +ata_scsi_set_invalid_field (dev, args->cmd,1 ,0xff ); +return 1 ; + } + +/* sector count, 64-bit */ + rbuf[0 ] = last_lba >> (8 *7 ); + rbuf[1 ] = last_lba >> (8 *6 ); + rbuf[2 ] = last_lba >> (8 *5 ); + rbuf[3 ] = last_lba >> (8 *4 ); + rbuf[4 ] = last_lba >> (8 *3 ); + rbuf[5 ] = last_lba >> (8 *2 ); + rbuf[6 ] = last_lba >> (8 *1 ); + rbuf[7 ] = last_lba; + +/* sector size */ + rbuf[8 ] = sector_size >> (8 *3 ); + rbuf[9 ] = sector_size >> (8 *2 ); + rbuf[10 ] = sector_size >> (8 *1 ); + rbuf[11 ] = sector_size; + +if (ata_id_zoned_cap (args->id) || args->dev->class ==ATA_DEV_ZAC ) + rbuf[12 ] = (1 <<4 );/* RC_BASIS */ + rbuf[13 ] = log2_per_phys; + rbuf[14 ] = (lowest_aligned >>8 ) &0x3f ; + rbuf[15 ] = lowest_aligned; + +if (ata_id_has_trim (args->id) && !(dev->quirks &ATA_QUIRK_NOTRIM )) { + rbuf[14 ] |=0x80 ;/* LBPME */ + +if (ata_id_has_zero_after_trim (args->id) && + dev->quirks &ATA_QUIRK_ZERO_AFTER_TRIM ) { +ata_dev_info (dev,"Enabling discard_zeroes_data\n" ); + rbuf[14 ] |=0x40 ;/* LBPRZ */ } -if (ata_id_zoned_cap (args->id) || - args->dev->class ==ATA_DEV_ZAC ) - rbuf[12 ] = (1 <<4 );/* RC_BASIS */ } +return 0 ; }
@@ -4333,14 +4344,8 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd)break ;case READ_CAPACITY : -ata_scsi_rbuf_fill (&args, ata_scsiop_read_cap); -break ; -case SERVICE_ACTION_IN_16 : -if ((scsicmd[1 ] &0x1f ) ==SAI_READ_CAPACITY_16 ) -ata_scsi_rbuf_fill (&args, ata_scsiop_read_cap); -else -ata_scsi_set_invalid_field (dev, cmd,1 ,0xff ); +ata_scsi_rbuf_fill (&args, ata_scsiop_read_cap);break ;case REPORT_LUNS :
Signature · 1 line
2.47.0
Damien Le Moal
maintainerPATCH 3/6 ata: libata-scsi: Refactor ata_scsiop_maint_in()
In reply to Damien Le MoalMove the check for MI_REPORT_SUPPORTED_OPERATION_CODES from ata_scsi_simulate() into ata_scsiop_maint_in() to simplify ata_scsi_simulate() code.
Furthermore, since an rbuff fill actor function returning a non-zero value causes no data to be returned for the command, directly return an error (return 1) for invalid command formt after setting the invalid field in cdb error.
--- drivers/ata/libata-scsi.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-)
drivers/ata/libata-scsi.c +11 -9
@@ -3388,12 +3388,16 @@ static unsigned int ata_scsiop_maint_in(struct ata_scsi_args *args, u8 *rbuf)struct ata_device *dev = args->dev;u8 *cdb = args->cmd->cmnd;u8 supported =0 , cdlp =0 , rwcdlp =0 ; -unsigned int err =0 ; + +if ((cdb[1 ] &0x1f ) !=MI_REPORT_SUPPORTED_OPERATION_CODES ) { +ata_scsi_set_invalid_field (dev, args->cmd,1 ,0xff ); +return 1 ; + }if (cdb[2 ] !=1 && cdb[2 ] !=3 ) {ata_dev_warn (dev,"invalid command format %d\n" , cdb[2 ]); - err =2 ; - goto out; +ata_scsi_set_invalid_field (dev, args->cmd,1 ,0xff ); +return 1 ; }switch (cdb[3 ]) {
@@ -3461,11 +3465,12 @@ static unsigned int ata_scsiop_maint_in(struct ata_scsi_args *args, u8 *rbuf)default :break ; } -out: +/* One command format */ rbuf[0 ] = rwcdlp; rbuf[1 ] = cdlp | supported; -return err; + +return 0 ; }/**
@@ -4377,10 +4382,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd)break ;case MAINTENANCE_IN : -if ((scsicmd[1 ] &0x1f ) ==MI_REPORT_SUPPORTED_OPERATION_CODES ) -ata_scsi_rbuf_fill (&args, ata_scsiop_maint_in); -else -ata_scsi_set_invalid_field (dev, cmd,1 ,0xff ); +ata_scsi_rbuf_fill (&args, ata_scsiop_maint_in);break ;/* all other commands */
Signature · 1 line
2.47.0
Re: [PATCH 3/6] ata: libata-scsi: Refactor ata_scsiop_maint_in()
Hi,
Quoted 24 lines · Damien Le Moal
Move the check for
MI_REPORT_SUPPORTED_OPERATION_CODESfromata_scsi_simulate()intoata_scsiop_maint_in()to simplifyata_scsi_simulate()code.Furthermore, since an rbuff fill actor function returning a non-zero value causes no data to be returned for the command, directly return an error (return 1) for invalid command formt after setting the invalid field in cdb error.
Signed-off-by Damien Le Moal <[email protected]>--- drivers/ata/libata-scsi.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-)drivers/ata/libata-scsi.c +1
-1@@ -3388,12 +3388,16 @@ static unsigned int ata_scsiop_maint_in(struct ata_scsi_args *args, u8 *rbuf)struct ata_device *dev = args->dev;u8 *cdb = args->cmd->cmnd;u8 supported =0 , cdlp =0 , rwcdlp =0 ; -unsigned int err =0 ; +
drivers/ata/libata-scsi.c static unsigned int ata_scsiop_maint_in(struct ata_scsi_args *args, u8 *rbuf) · line 3399
Quoted 10 lines
drivers/ata/libata-scsi.c +5
-2+if ((cdb[1 ] &0x1f ) !=MI_REPORT_SUPPORTED_OPERATION_CODES ) { +ata_scsi_set_invalid_field (dev, args->cmd,1 ,0xff ); +return 1 ; + }if (cdb[2 ] !=1 && cdb[2 ] !=3 ) {ata_dev_warn (dev,"invalid command format %d\n" , cdb[2 ]); - err =2 ; - goto out; +ata_scsi_set_invalid_field (dev, args->cmd,1 ,0xff );
Nit, but should this possibly be
ata_scsi_set_invalid_field(dev, args->cmd, 2, 0xff); ^
?
Thanks,
Guenter
Quoted 34 lines
drivers/ata/libata-scsi.c +5
-6+return 1 ; }switch (cdb[3 ]) {@@ -3461,11 +3465,12 @@ static unsigned int ata_scsiop_maint_in(struct ata_scsi_args *args, u8 *rbuf)default :break ; } -out: +/* One command format */ rbuf[0 ] = rwcdlp; rbuf[1 ] = cdlp | supported; -return err; + +return 0 ; }/** @@ -4377,10 +4382,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd)break ;case MAINTENANCE_IN : -if ((scsicmd[1 ] &0x1f ) ==MI_REPORT_SUPPORTED_OPERATION_CODES ) -ata_scsi_rbuf_fill (&args, ata_scsiop_maint_in); -else -ata_scsi_set_invalid_field (dev, cmd,1 ,0xff ); +ata_scsi_rbuf_fill (&args, ata_scsiop_maint_in);break ;/* all other commands */ Signature · 1 line
2.47.0
Damien Le Moal
maintainerRe: [PATCH 3/6] ata: libata-scsi: Refactor ata_scsiop_maint_in()
Quoted 39 lines · Guenter Roeck
Hi,
Quoted 24 lines · Damien Le Moal
Move the check for
MI_REPORT_SUPPORTED_OPERATION_CODESfromata_scsi_simulate()intoata_scsiop_maint_in()to simplifyata_scsi_simulate()code.Furthermore, since an rbuff fill actor function returning a non-zero value causes no data to be returned for the command, directly return an error (return 1) for invalid command formt after setting the invalid field in cdb error.
Signed-off-by Damien Le Moal <[email protected]>--- drivers/ata/libata-scsi.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-)drivers/ata/libata-scsi.c +1
-1@@ -3388,12 +3388,16 @@ static unsigned int ata_scsiop_maint_in(struct ata_scsi_args *args, u8 *rbuf)struct ata_device *dev = args->dev;u8 *cdb = args->cmd->cmnd;u8 supported =0 , cdlp =0 , rwcdlp =0 ; -unsigned int err =0 ; +drivers/ata/libata-scsi.c static unsigned int ata_scsiop_maint_in(struct ata_scsi_args *args, u8 *rbuf) · line 3399
Quoted 10 lines
drivers/ata/libata-scsi.c +5
-2+if ((cdb[1 ] &0x1f ) !=MI_REPORT_SUPPORTED_OPERATION_CODES ) { +ata_scsi_set_invalid_field (dev, args->cmd,1 ,0xff ); +return 1 ; + }if (cdb[2 ] !=1 && cdb[2 ] !=3 ) {ata_dev_warn (dev,"invalid command format %d\n" , cdb[2 ]); - err =2 ; - goto out; +ata_scsi_set_invalid_field (dev, args->cmd,1 ,0xff );Nit, but should this possibly be
Quoted 3 lines
ata_scsi_set_invalid_field(dev, args->cmd, 2, 0xff); ^?
Absolutely ! Good catch !
I will send a patch immediately.
Signature · 2 lines
Damien Le Moal Western Digital Research
Damien Le Moal
maintainerPATCH 4/6 ata: libata-scsi: Document all VPD page inquiry actors
In reply to Damien Le MoalAdd the missing kdoc comments for the ata_scsiop_inq_XX functions used to emulate access to VPD pages.
--- drivers/ata/libata-scsi.c | 54 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+)
drivers/ata/libata-scsi.c +54 -0
@@ -2052,6 +2052,16 @@ static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf)return 0 ; } +/** +* ata_scsiop_inq_b0 - Simulate INQUIRY VPD page B0, Block Limits +* @args: device IDENTIFY data / SCSI command of interest. +* @rbuf: Response buffer, to which simulated SCSI cmd output is sent. +* +* Return data for the VPD page B0h (Block Limits). +* +* LOCKING: +* spin_lock_irqsave(host lock) +*/ static unsigned int ata_scsiop_inq_b0 (struct ata_scsi_args *args,u8 *rbuf) {struct ata_device *dev = args->dev;
@@ -2092,6 +2102,17 @@ static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf)return 0 ; } +/** +* ata_scsiop_inq_b1 - Simulate INQUIRY VPD page B1, Block Device +* Characteristics +* @args: device IDENTIFY data / SCSI command of interest. +* @rbuf: Response buffer, to which simulated SCSI cmd output is sent. +* +* Return data for the VPD page B1h (Block Device Characteristics). +* +* LOCKING: +* spin_lock_irqsave(host lock) +*/ static unsigned int ata_scsiop_inq_b1 (struct ata_scsi_args *args,u8 *rbuf) {int form_factor =ata_id_form_factor (args->id);
@@ -2109,6 +2130,17 @@ static unsigned int ata_scsiop_inq_b1(struct ata_scsi_args *args, u8 *rbuf)return 0 ; } +/** +* ata_scsiop_inq_b2 - Simulate INQUIRY VPD page B2, Logical Block +* Provisioning +* @args: device IDENTIFY data / SCSI command of interest. +* @rbuf: Response buffer, to which simulated SCSI cmd output is sent. +* +* Return data for the VPD page B2h (Logical Block Provisioning). +* +* LOCKING: +* spin_lock_irqsave(host lock) +*/ static unsigned int ata_scsiop_inq_b2 (struct ata_scsi_args *args,u8 *rbuf) {/* SCSI Thin Provisioning VPD page: SBC-3 rev 22 or later */
@@ -2119,6 +2151,17 @@ static unsigned int ata_scsiop_inq_b2(struct ata_scsi_args *args, u8 *rbuf)return 0 ; } +/** +* ata_scsiop_inq_b6 - Simulate INQUIRY VPD page B6, Zoned Block Device +* Characteristics +* @args: device IDENTIFY data / SCSI command of interest. +* @rbuf: Response buffer, to which simulated SCSI cmd output is sent. +* +* Return data for the VPD page B2h (Zoned Block Device Characteristics). +* +* LOCKING: +* spin_lock_irqsave(host lock) +*/ static unsigned int ata_scsiop_inq_b6 (struct ata_scsi_args *args,u8 *rbuf) {if (!(args->dev->flags &ATA_DFLAG_ZAC )) {
@@ -2144,6 +2187,17 @@ static unsigned int ata_scsiop_inq_b6(struct ata_scsi_args *args, u8 *rbuf)return 0 ; } +/** +* ata_scsiop_inq_b9 - Simulate INQUIRY VPD page B9, Concurrent Positioning +* Ranges +* @args: device IDENTIFY data / SCSI command of interest. +* @rbuf: Response buffer, to which simulated SCSI cmd output is sent. +* +* Return data for the VPD page B9h (Concurrent Positioning Ranges). +* +* LOCKING: +* spin_lock_irqsave(host lock) +*/ static unsigned int ata_scsiop_inq_b9 (struct ata_scsi_args *args,u8 *rbuf) {struct ata_cpr_log *cpr_log = args->dev->cpr_log;
Signature · 1 line
2.47.0
Damien Le Moal
maintainerPATCH 5/6 ata: libata-scsi: Remove struct ata_scsi_args
In reply to Damien Le MoalThe data structure struct ata_scsi_args is used to pass the target ATA device, the SCSI command to simulate and the device identification data to ata_scsi_rbuf_fill() and to its actor function. This method of passing information does not improve the code in any way and in fact increases the number of pointer dereferences for no gains.
Drop this data structure by modifying the interface of ata_scsi_rbuf_fill() and its actor function to take an ATA device and a SCSI command as argument.
--- drivers/ata/libata-scsi.c | 241 ++++++++++++++++++++------------------ 1 file changed, 127 insertions(+), 114 deletions(-)
drivers/ata/libata-scsi.c +127 -114
@@ -1772,15 +1772,10 @@ static int ata_scsi_translate(struct ata_device *dev, struct scsi_cmnd *cmd,return SCSI_MLQUEUE_HOST_BUSY ; } -struct ata_scsi_args { -struct ata_device *dev; -u16 *id; -struct scsi_cmnd *cmd; -}; -/** * ata_scsi_rbuf_fill - wrapper for SCSI command simulators -* @args: device IDENTIFY data / SCSI command of interest. +* @dev: Target device. +* @cmd: SCSI command of interest. * @actor: Callback hook for desired SCSI command simulator * * Takes care of the hard work of simulating a SCSI command...
@@ -1793,30 +1788,30 @@ struct ata_scsi_args {* LOCKING: * spin_lock_irqsave(host lock) */ -static void ata_scsi_rbuf_fill (struct ata_scsi_args *args, -unsigned int (*actor)(struct ata_scsi_args *args,u8 *rbuf)) +static void ata_scsi_rbuf_fill (struct ata_device *dev,struct scsi_cmnd *cmd, +unsigned int (*actor)(struct ata_device *dev, +struct scsi_cmnd *cmd,u8 *rbuf)) {unsigned int rc; -struct scsi_cmnd *cmd = args->cmd;unsigned long flags;spin_lock_irqsave (&ata_scsi_rbuf_lock, flags);memset (ata_scsi_rbuf,0 ,ATA_SCSI_RBUF_SIZE ); - rc =actor (args, ata_scsi_rbuf); -if (rc ==0 ) + rc =actor (dev, cmd, ata_scsi_rbuf); +if (rc ==0 ) {sg_copy_from_buffer (scsi_sglist (cmd),scsi_sg_count (cmd), ata_scsi_rbuf,ATA_SCSI_RBUF_SIZE ); + cmd->result =SAM_STAT_GOOD ; + }spin_unlock_irqrestore (&ata_scsi_rbuf_lock, flags); - -if (rc ==0 ) - cmd->result =SAM_STAT_GOOD ; }/** * ata_scsiop_inq_std - Simulate standard INQUIRY command -* @args: device IDENTIFY data / SCSI command of interest. +* @dev: Target device. +* @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Returns standard device identification data associated
@@ -1825,7 +1820,8 @@ static void ata_scsi_rbuf_fill(struct ata_scsi_args *args,* LOCKING: * spin_lock_irqsave(host lock) */ -static unsigned int ata_scsiop_inq_std (struct ata_scsi_args *args,u8 *rbuf) +static unsigned int ata_scsiop_inq_std (struct ata_device *dev, +struct scsi_cmnd *cmd,u8 *rbuf) {static const u8 versions[] = {0x00 ,
@@ -1866,30 +1862,30 @@ static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf)* Set the SCSI Removable Media Bit (RMB) if the ATA removable media * device bit (obsolete since ATA-8 ACS) is set. */ -if (ata_id_removable (args->id)) +if (ata_id_removable (dev->id)) hdr[1 ] |= (1 <<7 ); -if (args->dev->class ==ATA_DEV_ZAC ) { +if (dev->class ==ATA_DEV_ZAC ) { hdr[0 ] =TYPE_ZBC ; hdr[2 ] =0x7 ;/* claim SPC-5 version compatibility */ } -if (args->dev->flags &ATA_DFLAG_CDL ) +if (dev->flags &ATA_DFLAG_CDL ) hdr[2 ] =0xd ;/* claim SPC-6 version compatibility */ memcpy (rbuf, hdr,sizeof (hdr));memcpy (&rbuf[8 ],"ATA " ,8 ); -ata_id_string (args->id, &rbuf[16 ],ATA_ID_PROD ,16 ); +ata_id_string (dev->id, &rbuf[16 ],ATA_ID_PROD ,16 );/* From SAT, use last 2 words from fw rev unless they are spaces */ -ata_id_string (args->id, &rbuf[32 ],ATA_ID_FW_REV +2 ,4 ); +ata_id_string (dev->id, &rbuf[32 ],ATA_ID_FW_REV +2 ,4 );if (strncmp (&rbuf[32 ]," " ,4 ) ==0 ) -ata_id_string (args->id, &rbuf[32 ],ATA_ID_FW_REV ,4 ); +ata_id_string (dev->id, &rbuf[32 ],ATA_ID_FW_REV ,4 );if (rbuf[32 ] ==0 || rbuf[32 ] ==' ' )memcpy (&rbuf[32 ],"n/a " ,4 ); -if (ata_id_zoned_cap (args->id) || args->dev->class ==ATA_DEV_ZAC ) +if (ata_id_zoned_cap (dev->id) || dev->class ==ATA_DEV_ZAC )memcpy (rbuf +58 , versions_zbc,sizeof (versions_zbc));else memcpy (rbuf +58 , versions,sizeof (versions));
@@ -1899,7 +1895,8 @@ static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf)/** * ata_scsiop_inq_00 - Simulate INQUIRY VPD page 0, list of pages -* @args: device IDENTIFY data / SCSI command of interest. +* @dev: Target device. +* @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Returns list of inquiry VPD pages available.
@@ -1907,7 +1904,8 @@ static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf)* LOCKING: * spin_lock_irqsave(host lock) */ -static unsigned int ata_scsiop_inq_00 (struct ata_scsi_args *args,u8 *rbuf) +static unsigned int ata_scsiop_inq_00 (struct ata_device *dev, +struct scsi_cmnd *cmd,u8 *rbuf) {int i, num_pages =0 ;static const u8 pages[] = {
@@ -1924,7 +1922,7 @@ static unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf)for (i =0 ; i <sizeof (pages); i++) {if (pages[i] ==0xb6 && - !(args->dev->flags &ATA_DFLAG_ZAC )) + !(dev->flags &ATA_DFLAG_ZAC ))continue ; rbuf[num_pages +4 ] = pages[i]; num_pages++;
@@ -1935,7 +1933,8 @@ static unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf)/** * ata_scsiop_inq_80 - Simulate INQUIRY VPD page 80, device serial number -* @args: device IDENTIFY data / SCSI command of interest. +* @dev: Target device. +* @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Returns ATA device serial number.
@@ -1943,7 +1942,8 @@ static unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf)* LOCKING: * spin_lock_irqsave(host lock) */ -static unsigned int ata_scsiop_inq_80 (struct ata_scsi_args *args,u8 *rbuf) +static unsigned int ata_scsiop_inq_80 (struct ata_device *dev, +struct scsi_cmnd *cmd,u8 *rbuf) {static const u8 hdr[] = {0 ,
@@ -1953,14 +1953,15 @@ static unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf) };memcpy (rbuf, hdr,sizeof (hdr)); -ata_id_string (args->id, (unsigned char *) &rbuf[4 ], +ata_id_string (dev->id, (unsigned char *) &rbuf[4 ],ATA_ID_SERNO ,ATA_ID_SERNO_LEN );return 0 ; }/** * ata_scsiop_inq_83 - Simulate INQUIRY VPD page 83, device identity -* @args: device IDENTIFY data / SCSI command of interest. +* @dev: Target device. +* @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Yields two logical unit device identification designators:
@@ -1971,7 +1972,8 @@ static unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf)* LOCKING: * spin_lock_irqsave(host lock) */ -static unsigned int ata_scsiop_inq_83 (struct ata_scsi_args *args,u8 *rbuf) +static unsigned int ata_scsiop_inq_83 (struct ata_device *dev, +struct scsi_cmnd *cmd,u8 *rbuf) {const int sat_model_serial_desc_len =68 ;int num;
@@ -1983,7 +1985,7 @@ static unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf) rbuf[num +0 ] =2 ; rbuf[num +3 ] =ATA_ID_SERNO_LEN ; num +=4 ; -ata_id_string (args->id, (unsigned char *) rbuf + num, +ata_id_string (dev->id, (unsigned char *) rbuf + num,ATA_ID_SERNO ,ATA_ID_SERNO_LEN ); num +=ATA_ID_SERNO_LEN ;
@@ -1995,21 +1997,21 @@ static unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf) num +=4 ;memcpy (rbuf + num,"ATA " ,8 ); num +=8 ; -ata_id_string (args->id, (unsigned char *) rbuf + num,ATA_ID_PROD , +ata_id_string (dev->id, (unsigned char *) rbuf + num,ATA_ID_PROD ,ATA_ID_PROD_LEN ); num +=ATA_ID_PROD_LEN ; -ata_id_string (args->id, (unsigned char *) rbuf + num,ATA_ID_SERNO , +ata_id_string (dev->id, (unsigned char *) rbuf + num,ATA_ID_SERNO ,ATA_ID_SERNO_LEN ); num +=ATA_ID_SERNO_LEN ; -if (ata_id_has_wwn (args->id)) { +if (ata_id_has_wwn (dev->id)) {/* SAT defined lu world wide name */ /* piv=0, assoc=lu, code_set=binary, designator=NAA */ rbuf[num +0 ] =1 ; rbuf[num +1 ] =3 ; rbuf[num +3 ] =ATA_ID_WWN_LEN ; num +=4 ; -ata_id_string (args->id, (unsigned char *) rbuf + num, +ata_id_string (dev->id, (unsigned char *) rbuf + num,ATA_ID_WWN ,ATA_ID_WWN_LEN ); num +=ATA_ID_WWN_LEN ; }
@@ -2019,7 +2021,8 @@ static unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf)/** * ata_scsiop_inq_89 - Simulate INQUIRY VPD page 89, ATA info -* @args: device IDENTIFY data / SCSI command of interest. +* @dev: Target device. +* @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Yields SAT-specified ATA VPD page.
@@ -2027,7 +2030,8 @@ static unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf)* LOCKING: * spin_lock_irqsave(host lock) */ -static unsigned int ata_scsiop_inq_89 (struct ata_scsi_args *args,u8 *rbuf) +static unsigned int ata_scsiop_inq_89 (struct ata_device *dev, +struct scsi_cmnd *cmd,u8 *rbuf) { rbuf[1 ] =0x89 ;/* our page code */ rbuf[2 ] = (0x238 >>8 );/* page size fixed at 238h */
@@ -2048,13 +2052,14 @@ static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf) rbuf[56 ] =ATA_CMD_ID_ATA ; -memcpy (&rbuf[60 ], &args->id[0 ],512 ); +memcpy (&rbuf[60 ], &dev->id[0 ],512 );return 0 ; }/** * ata_scsiop_inq_b0 - Simulate INQUIRY VPD page B0, Block Limits -* @args: device IDENTIFY data / SCSI command of interest. +* @dev: Target device. +* @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Return data for the VPD page B0h (Block Limits).
@@ -2062,9 +2067,9 @@ static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf)* LOCKING: * spin_lock_irqsave(host lock) */ -static unsigned int ata_scsiop_inq_b0 (struct ata_scsi_args *args,u8 *rbuf) +static unsigned int ata_scsiop_inq_b0 (struct ata_device *dev, +struct scsi_cmnd *cmd,u8 *rbuf) { -struct ata_device *dev = args->dev;u16 min_io_sectors; rbuf[1 ] =0xb0 ;
@@ -2077,7 +2082,7 @@ static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf)* logical than physical sector size we need to figure out what the * latter is. */ - min_io_sectors =1 <<ata_id_log2_per_physical_sector (args->id); + min_io_sectors =1 <<ata_id_log2_per_physical_sector (dev->id);put_unaligned_be16 (min_io_sectors, &rbuf[6 ]);/*
@@ -2089,7 +2094,7 @@ static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf)* that we support some form of unmap - in thise case via WRITE SAME * with the unmap bit set. */ -if (ata_id_has_trim (args->id)) { +if (ata_id_has_trim (dev->id)) {u64 max_blocks =65535 *ATA_MAX_TRIM_RNUM ;if (dev->quirks &ATA_QUIRK_MAX_TRIM_128M )
@@ -2105,7 +2110,8 @@ static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf)/** * ata_scsiop_inq_b1 - Simulate INQUIRY VPD page B1, Block Device * Characteristics -* @args: device IDENTIFY data / SCSI command of interest. +* @dev: Target device. +* @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Return data for the VPD page B1h (Block Device Characteristics).
@@ -2113,11 +2119,12 @@ static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf)* LOCKING: * spin_lock_irqsave(host lock) */ -static unsigned int ata_scsiop_inq_b1 (struct ata_scsi_args *args,u8 *rbuf) +static unsigned int ata_scsiop_inq_b1 (struct ata_device *dev, +struct scsi_cmnd *cmd,u8 *rbuf) { -int form_factor =ata_id_form_factor (args->id); -int media_rotation_rate =ata_id_rotation_rate (args->id); -u8 zoned =ata_id_zoned_cap (args->id); +int form_factor =ata_id_form_factor (dev->id); +int media_rotation_rate =ata_id_rotation_rate (dev->id); +u8 zoned =ata_id_zoned_cap (dev->id); rbuf[1 ] =0xb1 ; rbuf[3 ] =0x3c ;
@@ -2133,7 +2140,8 @@ static unsigned int ata_scsiop_inq_b1(struct ata_scsi_args *args, u8 *rbuf)/** * ata_scsiop_inq_b2 - Simulate INQUIRY VPD page B2, Logical Block * Provisioning -* @args: device IDENTIFY data / SCSI command of interest. +* @dev: Target device. +* @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Return data for the VPD page B2h (Logical Block Provisioning).
@@ -2141,7 +2149,8 @@ static unsigned int ata_scsiop_inq_b1(struct ata_scsi_args *args, u8 *rbuf)* LOCKING: * spin_lock_irqsave(host lock) */ -static unsigned int ata_scsiop_inq_b2 (struct ata_scsi_args *args,u8 *rbuf) +static unsigned int ata_scsiop_inq_b2 (struct ata_device *dev, +struct scsi_cmnd *cmd,u8 *rbuf) {/* SCSI Thin Provisioning VPD page: SBC-3 rev 22 or later */ rbuf[1 ] =0xb2 ;
@@ -2154,7 +2163,8 @@ static unsigned int ata_scsiop_inq_b2(struct ata_scsi_args *args, u8 *rbuf)/** * ata_scsiop_inq_b6 - Simulate INQUIRY VPD page B6, Zoned Block Device * Characteristics -* @args: device IDENTIFY data / SCSI command of interest. +* @dev: Target device. +* @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Return data for the VPD page B2h (Zoned Block Device Characteristics).
@@ -2162,10 +2172,11 @@ static unsigned int ata_scsiop_inq_b2(struct ata_scsi_args *args, u8 *rbuf)* LOCKING: * spin_lock_irqsave(host lock) */ -static unsigned int ata_scsiop_inq_b6 (struct ata_scsi_args *args,u8 *rbuf) +static unsigned int ata_scsiop_inq_b6 (struct ata_device *dev, +struct scsi_cmnd *cmd,u8 *rbuf) { -if (!(args->dev->flags &ATA_DFLAG_ZAC )) { -ata_scsi_set_invalid_field (args->dev, args->cmd,2 ,0xff ); +if (!(dev->flags &ATA_DFLAG_ZAC )) { +ata_scsi_set_invalid_field (dev, cmd,2 ,0xff );return 1 ; }
@@ -2178,11 +2189,11 @@ static unsigned int ata_scsiop_inq_b6(struct ata_scsi_args *args, u8 *rbuf)/* * URSWRZ bit is only meaningful for host-managed ZAC drives */ -if (args->dev->zac_zoned_cap &1 ) +if (dev->zac_zoned_cap &1 ) rbuf[4 ] |=1 ; -put_unaligned_be32 (args->dev->zac_zones_optimal_open, &rbuf[8 ]); -put_unaligned_be32 (args->dev->zac_zones_optimal_nonseq, &rbuf[12 ]); -put_unaligned_be32 (args->dev->zac_zones_max_open, &rbuf[16 ]); +put_unaligned_be32 (dev->zac_zones_optimal_open, &rbuf[8 ]); +put_unaligned_be32 (dev->zac_zones_optimal_nonseq, &rbuf[12 ]); +put_unaligned_be32 (dev->zac_zones_max_open, &rbuf[16 ]);return 0 ; }
@@ -2190,7 +2201,8 @@ static unsigned int ata_scsiop_inq_b6(struct ata_scsi_args *args, u8 *rbuf)/** * ata_scsiop_inq_b9 - Simulate INQUIRY VPD page B9, Concurrent Positioning * Ranges -* @args: device IDENTIFY data / SCSI command of interest. +* @dev: Target device. +* @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Return data for the VPD page B9h (Concurrent Positioning Ranges).
@@ -2198,14 +2210,15 @@ static unsigned int ata_scsiop_inq_b6(struct ata_scsi_args *args, u8 *rbuf)* LOCKING: * spin_lock_irqsave(host lock) */ -static unsigned int ata_scsiop_inq_b9 (struct ata_scsi_args *args,u8 *rbuf) +static unsigned int ata_scsiop_inq_b9 (struct ata_device *dev, +struct scsi_cmnd *cmd,u8 *rbuf) { -struct ata_cpr_log *cpr_log = args->dev->cpr_log; +struct ata_cpr_log *cpr_log = dev->cpr_log;u8 *desc = &rbuf[64 ];int i;if (!cpr_log) { -ata_scsi_set_invalid_field (args->dev, args->cmd,2 ,0xff ); +ata_scsi_set_invalid_field (dev, cmd,2 ,0xff );return 1 ; }
@@ -2225,7 +2238,8 @@ static unsigned int ata_scsiop_inq_b9(struct ata_scsi_args *args, u8 *rbuf)/** * ata_scsiop_inquiry - Simulate INQUIRY command -* @args: device IDENTIFY data / SCSI command of interest. +* @dev: Target device. +* @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Returns data associated with an INQUIRY command output.
@@ -2233,10 +2247,9 @@ static unsigned int ata_scsiop_inq_b9(struct ata_scsi_args *args, u8 *rbuf)* LOCKING: * spin_lock_irqsave(host lock) */ -static unsigned int ata_scsiop_inquiry (struct ata_scsi_args *args,u8 *rbuf) +static unsigned int ata_scsiop_inquiry (struct ata_device *dev, +struct scsi_cmnd *cmd,u8 *rbuf) { -struct ata_device *dev = args->dev; -struct scsi_cmnd *cmd = args->cmd;const u8 *scsicmd = cmd->cmnd;/* is CmdDt set? */
@@ -2247,27 +2260,27 @@ static unsigned int ata_scsiop_inquiry(struct ata_scsi_args *args, u8 *rbuf)/* Is EVPD clear? */ if ((scsicmd[1 ] &1 ) ==0 ) -return ata_scsiop_inq_std (args, rbuf); +return ata_scsiop_inq_std (dev, cmd, rbuf);switch (scsicmd[2 ]) {case 0x00 : -return ata_scsiop_inq_00 (args, rbuf); +return ata_scsiop_inq_00 (dev, cmd, rbuf);case 0x80 : -return ata_scsiop_inq_80 (args, rbuf); +return ata_scsiop_inq_80 (dev, cmd, rbuf);case 0x83 : -return ata_scsiop_inq_83 (args, rbuf); +return ata_scsiop_inq_83 (dev, cmd, rbuf);case 0x89 : -return ata_scsiop_inq_89 (args, rbuf); +return ata_scsiop_inq_89 (dev, cmd, rbuf);case 0xb0 : -return ata_scsiop_inq_b0 (args, rbuf); +return ata_scsiop_inq_b0 (dev, cmd, rbuf);case 0xb1 : -return ata_scsiop_inq_b1 (args, rbuf); +return ata_scsiop_inq_b1 (dev, cmd, rbuf);case 0xb2 : -return ata_scsiop_inq_b2 (args, rbuf); +return ata_scsiop_inq_b2 (dev, cmd, rbuf);case 0xb6 : -return ata_scsiop_inq_b6 (args, rbuf); +return ata_scsiop_inq_b6 (dev, cmd, rbuf);case 0xb9 : -return ata_scsiop_inq_b9 (args, rbuf); +return ata_scsiop_inq_b9 (dev, cmd, rbuf);default :ata_scsi_set_invalid_field (dev, cmd,2 ,0xff );return 1 ;
@@ -2494,7 +2507,8 @@ static unsigned int ata_msense_rw_recovery(u8 *buf, bool changeable)/** * ata_scsiop_mode_sense - Simulate MODE SENSE 6, 10 commands -* @args: device IDENTIFY data / SCSI command of interest. +* @dev: Target device. +* @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Simulate MODE SENSE commands. Assume this is invoked for direct
@@ -2504,10 +2518,10 @@ static unsigned int ata_msense_rw_recovery(u8 *buf, bool changeable)* LOCKING: * spin_lock_irqsave(host lock) */ -static unsigned int ata_scsiop_mode_sense (struct ata_scsi_args *args,u8 *rbuf) +static unsigned int ata_scsiop_mode_sense (struct ata_device *dev, +struct scsi_cmnd *cmd,u8 *rbuf) { -struct ata_device *dev = args->dev; -u8 *scsicmd = args->cmd->cmnd, *p = rbuf; +u8 *scsicmd = cmd->cmnd, *p = rbuf;static const u8 sat_blk_desc[] = {0 ,0 ,0 ,0 ,/* number of blocks: sat unspecified */ 0 ,
@@ -2572,17 +2586,17 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf)break ;case CACHE_MPAGE : - p +=ata_msense_caching (args->id, p, page_control ==1 ); + p +=ata_msense_caching (dev->id, p, page_control ==1 );break ;case CONTROL_MPAGE : - p +=ata_msense_control (args->dev, p, spg, page_control ==1 ); + p +=ata_msense_control (dev, p, spg, page_control ==1 );break ;case ALL_MPAGES : p +=ata_msense_rw_recovery (p, page_control ==1 ); - p +=ata_msense_caching (args->id, p, page_control ==1 ); - p +=ata_msense_control (args->dev, p, spg, page_control ==1 ); + p +=ata_msense_caching (dev->id, p, page_control ==1 ); + p +=ata_msense_control (dev, p, spg, page_control ==1 );break ;default :/* invalid page code */
@@ -2611,18 +2625,19 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf)return 0 ; invalid_fld: -ata_scsi_set_invalid_field (dev, args->cmd, fp, bp); +ata_scsi_set_invalid_field (dev, cmd, fp, bp);return 1 ; saving_not_supp: -ata_scsi_set_sense (dev, args->cmd,ILLEGAL_REQUEST ,0x39 ,0x0 ); +ata_scsi_set_sense (dev, cmd,ILLEGAL_REQUEST ,0x39 ,0x0 );/* "Saving parameters not supported" */ return 1 ; }/** * ata_scsiop_read_cap - Simulate READ CAPACITY[ 16] commands -* @args: device IDENTIFY data / SCSI command of interest. +* @dev: Target device. +* @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Simulate READ CAPACITY commands.
@@ -2630,10 +2645,10 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf)* LOCKING: * None. */ -static unsigned int ata_scsiop_read_cap (struct ata_scsi_args *args,u8 *rbuf) +static unsigned int ata_scsiop_read_cap (struct ata_device *dev, +struct scsi_cmnd *cmd,u8 *rbuf) { -struct ata_device *dev = args->dev; -u8 *scsicmd = args->cmd->cmnd; +u8 *scsicmd = cmd->cmnd;u64 last_lba = dev->n_sectors -1 ;/* LBA of the last block */ u32 sector_size;/* physical sector size in bytes */ u8 log2_per_phys;
@@ -2668,7 +2683,7 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf)*/ if (scsicmd[0 ] !=SERVICE_ACTION_IN_16 || (scsicmd[1 ] &0x1f ) !=SAI_READ_CAPACITY_16 ) { -ata_scsi_set_invalid_field (dev, args->cmd,1 ,0xff ); +ata_scsi_set_invalid_field (dev, cmd,1 ,0xff );return 1 ; }
@@ -2688,16 +2703,16 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf) rbuf[10 ] = sector_size >> (8 *1 ); rbuf[11 ] = sector_size; -if (ata_id_zoned_cap (args->id) || args->dev->class ==ATA_DEV_ZAC ) +if (ata_id_zoned_cap (dev->id) || dev->class ==ATA_DEV_ZAC ) rbuf[12 ] = (1 <<4 );/* RC_BASIS */ rbuf[13 ] = log2_per_phys; rbuf[14 ] = (lowest_aligned >>8 ) &0x3f ; rbuf[15 ] = lowest_aligned; -if (ata_id_has_trim (args->id) && !(dev->quirks &ATA_QUIRK_NOTRIM )) { +if (ata_id_has_trim (dev->id) && !(dev->quirks &ATA_QUIRK_NOTRIM )) { rbuf[14 ] |=0x80 ;/* LBPME */ -if (ata_id_has_zero_after_trim (args->id) && +if (ata_id_has_zero_after_trim (dev->id) && dev->quirks &ATA_QUIRK_ZERO_AFTER_TRIM ) {ata_dev_info (dev,"Enabling discard_zeroes_data\n" ); rbuf[14 ] |=0x40 ;/* LBPRZ */
@@ -2709,7 +2724,8 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf)/** * ata_scsiop_report_luns - Simulate REPORT LUNS command -* @args: device IDENTIFY data / SCSI command of interest. +* @dev: Target device. +* @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Simulate REPORT LUNS command.
@@ -2717,7 +2733,8 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf)* LOCKING: * spin_lock_irqsave(host lock) */ -static unsigned int ata_scsiop_report_luns (struct ata_scsi_args *args,u8 *rbuf) +static unsigned int ata_scsiop_report_luns (struct ata_device *dev, +struct scsi_cmnd *cmd,u8 *rbuf) { rbuf[3 ] =8 ;/* just one lun, LUN 0, size 8 bytes */
@@ -3429,7 +3446,8 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc)/** * ata_scsiop_maint_in - Simulate a subset of MAINTENANCE_IN -* @args: device MAINTENANCE_IN data / SCSI command of interest. +* @dev: Target device. +* @cmd: SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * * Yields a subset to satisfy scsi_report_opcode()
@@ -3437,20 +3455,20 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc)* LOCKING: * spin_lock_irqsave(host lock) */ -static unsigned int ata_scsiop_maint_in (struct ata_scsi_args *args,u8 *rbuf) +static unsigned int ata_scsiop_maint_in (struct ata_device *dev, +struct scsi_cmnd *cmd,u8 *rbuf) { -struct ata_device *dev = args->dev; -u8 *cdb = args->cmd->cmnd; +u8 *cdb = cmd->cmnd;u8 supported =0 , cdlp =0 , rwcdlp =0 ;if ((cdb[1 ] &0x1f ) !=MI_REPORT_SUPPORTED_OPERATION_CODES ) { -ata_scsi_set_invalid_field (dev, args->cmd,1 ,0xff ); +ata_scsi_set_invalid_field (dev, cmd,1 ,0xff );return 1 ; }if (cdb[2 ] !=1 && cdb[2 ] !=3 ) {ata_dev_warn (dev,"invalid command format %d\n" , cdb[2 ]); -ata_scsi_set_invalid_field (dev, args->cmd,1 ,0xff ); +ata_scsi_set_invalid_field (dev, cmd,1 ,0xff );return 1 ; }
@@ -4384,31 +4402,26 @@ EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);void ata_scsi_simulate (struct ata_device *dev,struct scsi_cmnd *cmd) { -struct ata_scsi_args args;const u8 *scsicmd = cmd->cmnd;u8 tmp8; - args.dev = dev; - args.id = dev->id; - args.cmd = cmd; -switch (scsicmd[0 ]) {case INQUIRY : -ata_scsi_rbuf_fill (&args, ata_scsiop_inquiry); +ata_scsi_rbuf_fill (dev, cmd, ata_scsiop_inquiry);break ;case MODE_SENSE :case MODE_SENSE_10 : -ata_scsi_rbuf_fill (&args, ata_scsiop_mode_sense); +ata_scsi_rbuf_fill (dev, cmd, ata_scsiop_mode_sense);break ;case READ_CAPACITY :case SERVICE_ACTION_IN_16 : -ata_scsi_rbuf_fill (&args, ata_scsiop_read_cap); +ata_scsi_rbuf_fill (dev, cmd, ata_scsiop_read_cap);break ;case REPORT_LUNS : -ata_scsi_rbuf_fill (&args, ata_scsiop_report_luns); +ata_scsi_rbuf_fill (dev, cmd, ata_scsiop_report_luns);break ;case REQUEST_SENSE :
@@ -4436,7 +4449,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd)break ;case MAINTENANCE_IN : -ata_scsi_rbuf_fill (&args, ata_scsiop_maint_in); +ata_scsi_rbuf_fill (dev, cmd, ata_scsiop_maint_in);break ;/* all other commands */
Signature · 1 line
2.47.0
Damien Le Moal
maintainerPATCH 6/6 ata: libata-scsi: Return residual for emulated SCSI commands
In reply to Damien Le MoalThe function ata_scsi_rbuf_fill() used to fill the reply buffer of emulated SCSI commands always copies the ATA reply buffer (ata_scsi_rbuf) up to the size of the SCSI command buffer (the transfer length for the command), even if the reply is shorter than the SCSI command buffer. This leads to issuers of the SCSI command to always get a result without any residual (resid is always 0) despite the potentially shorter reply for the command.
Modify all fill actors used by ata_scsi_rbuf_fill() to return the number of bytes filled for the reply and 0 in case of error. Using this value, add a call to scsi_set_resid() in ata_scsi_rbuf_fill() to set the correct residual for the SCSI command when the reply length is shorter than the command buffer.
--- drivers/ata/libata-scsi.c | 81 +++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 34 deletions(-)
drivers/ata/libata-scsi.c +47 -34
@@ -1792,17 +1792,19 @@ static void ata_scsi_rbuf_fill(struct ata_device *dev, struct scsi_cmnd *cmd,unsigned int (*actor)(struct ata_device *dev, struct scsi_cmnd *cmd, u8 *rbuf)) { -unsigned int rc;unsigned long flags; +unsigned int len;spin_lock_irqsave (&ata_scsi_rbuf_lock, flags);memset (ata_scsi_rbuf,0 ,ATA_SCSI_RBUF_SIZE ); - rc =actor (dev, cmd, ata_scsi_rbuf); -if (rc ==0 ) { + len =actor (dev, cmd, ata_scsi_rbuf); +if (len) {sg_copy_from_buffer (scsi_sglist (cmd),scsi_sg_count (cmd), ata_scsi_rbuf,ATA_SCSI_RBUF_SIZE ); cmd->result =SAM_STAT_GOOD ; +if (scsi_bufflen (cmd) > len) +scsi_set_resid (cmd,scsi_bufflen (cmd) - len); }spin_unlock_irqrestore (&ata_scsi_rbuf_lock, flags);
@@ -1890,7 +1892,11 @@ static unsigned int ata_scsiop_inq_std(struct ata_device *dev,else memcpy (rbuf +58 , versions,sizeof (versions)); -return 0 ; +/* +* Include all 8 possible version descriptors, even if not all of +* them are popoulated. +*/ +return 96 ; }/**
@@ -1928,7 +1934,8 @@ static unsigned int ata_scsiop_inq_00(struct ata_device *dev, num_pages++; } rbuf[3 ] = num_pages;/* number of supported VPD pages */ -return 0 ; + +return get_unaligned_be16 (&rbuf[2 ]) +4 ; }/**
@@ -1955,7 +1962,8 @@ static unsigned int ata_scsiop_inq_80(struct ata_device *dev,memcpy (rbuf, hdr,sizeof (hdr));ata_id_string (dev->id, (unsigned char *) &rbuf[4 ],ATA_ID_SERNO ,ATA_ID_SERNO_LEN ); -return 0 ; + +return get_unaligned_be16 (&rbuf[2 ]) +4 ; }/**
@@ -2016,7 +2024,8 @@ static unsigned int ata_scsiop_inq_83(struct ata_device *dev, num +=ATA_ID_WWN_LEN ; } rbuf[3 ] = num -4 ;/* page len (assume less than 256 bytes) */ -return 0 ; + +return get_unaligned_be16 (&rbuf[2 ]) +4 ; }/**
@@ -2053,7 +2062,8 @@ static unsigned int ata_scsiop_inq_89(struct ata_device *dev, rbuf[56 ] =ATA_CMD_ID_ATA ;memcpy (&rbuf[60 ], &dev->id[0 ],512 ); -return 0 ; + +return get_unaligned_be16 (&rbuf[2 ]) +4 ; }/**
@@ -2104,7 +2114,7 @@ static unsigned int ata_scsiop_inq_b0(struct ata_device *dev,put_unaligned_be32 (1 , &rbuf[28 ]); } -return 0 ; +return get_unaligned_be16 (&rbuf[2 ]) +4 ; }/**
@@ -2134,7 +2144,7 @@ static unsigned int ata_scsiop_inq_b1(struct ata_device *dev,if (zoned) rbuf[8 ] = (zoned <<4 ); -return 0 ; +return get_unaligned_be16 (&rbuf[2 ]) +4 ; }/**
@@ -2157,7 +2167,7 @@ static unsigned int ata_scsiop_inq_b2(struct ata_device *dev, rbuf[3 ] =0x4 ; rbuf[5 ] =1 <<6 ;/* TPWS */ -return 0 ; +return get_unaligned_be16 (&rbuf[2 ]) +4 ; }/**
@@ -2177,7 +2187,7 @@ static unsigned int ata_scsiop_inq_b6(struct ata_device *dev, {if (!(dev->flags &ATA_DFLAG_ZAC )) {ata_scsi_set_invalid_field (dev, cmd,2 ,0xff ); -return 1 ; +return 0 ; }/*
@@ -2195,7 +2205,7 @@ static unsigned int ata_scsiop_inq_b6(struct ata_device *dev,put_unaligned_be32 (dev->zac_zones_optimal_nonseq, &rbuf[12 ]);put_unaligned_be32 (dev->zac_zones_max_open, &rbuf[16 ]); -return 0 ; +return get_unaligned_be16 (&rbuf[2 ]) +4 ; }/**
@@ -2219,7 +2229,7 @@ static unsigned int ata_scsiop_inq_b9(struct ata_device *dev,if (!cpr_log) {ata_scsi_set_invalid_field (dev, cmd,2 ,0xff ); -return 1 ; +return 0 ; }/* SCSI Concurrent Positioning Ranges VPD page: SBC-5 rev 1 or later */
@@ -2233,7 +2243,7 @@ static unsigned int ata_scsiop_inq_b9(struct ata_device *dev,put_unaligned_be64 (cpr_log->cpr[i].num_lbas, &desc[16 ]); } -return 0 ; +return get_unaligned_be16 (&rbuf[2 ]) +4 ; }/**
@@ -2255,7 +2265,7 @@ static unsigned int ata_scsiop_inquiry(struct ata_device *dev,/* is CmdDt set? */ if (scsicmd[1 ] &2 ) {ata_scsi_set_invalid_field (dev, cmd,1 ,0xff ); -return 1 ; +return 0 ; }/* Is EVPD clear? */
@@ -2283,7 +2293,7 @@ static unsigned int ata_scsiop_inquiry(struct ata_device *dev,return ata_scsiop_inq_b9 (dev, cmd, rbuf);default :ata_scsi_set_invalid_field (dev, cmd,2 ,0xff ); -return 1 ; +return 0 ; } }
@@ -2614,24 +2624,27 @@ static unsigned int ata_scsiop_mode_sense(struct ata_device *dev, rbuf[3 ] =sizeof (sat_blk_desc);memcpy (rbuf +4 , sat_blk_desc,sizeof (sat_blk_desc)); } - }else { -put_unaligned_be16 (p - rbuf -2 , &rbuf[0 ]); - rbuf[3 ] |= dpofua; -if (ebd) { - rbuf[7 ] =sizeof (sat_blk_desc); -memcpy (rbuf +8 , sat_blk_desc,sizeof (sat_blk_desc)); - } + +return rbuf[0 ] +1 ; + } + +put_unaligned_be16 (p - rbuf -2 , &rbuf[0 ]); + rbuf[3 ] |= dpofua; +if (ebd) { + rbuf[7 ] =sizeof (sat_blk_desc); +memcpy (rbuf +8 , sat_blk_desc,sizeof (sat_blk_desc)); } -return 0 ; + +return get_unaligned_be16 (&rbuf[0 ]) +2 ; invalid_fld:ata_scsi_set_invalid_field (dev, cmd, fp, bp); -return 1 ; +return 0 ; saving_not_supp:ata_scsi_set_sense (dev, cmd,ILLEGAL_REQUEST ,0x39 ,0x0 );/* "Saving parameters not supported" */ -return 1 ; +return 0 ; }/**
@@ -2674,7 +2687,7 @@ static unsigned int ata_scsiop_read_cap(struct ata_device *dev, rbuf[6 ] = sector_size >> (8 *1 ); rbuf[7 ] = sector_size; -return 0 ; +return 8 ; }/*
@@ -2684,7 +2697,7 @@ static unsigned int ata_scsiop_read_cap(struct ata_device *dev,if (scsicmd[0 ] !=SERVICE_ACTION_IN_16 || (scsicmd[1 ] &0x1f ) !=SAI_READ_CAPACITY_16 ) {ata_scsi_set_invalid_field (dev, cmd,1 ,0xff ); -return 1 ; +return 0 ; }/* sector count, 64-bit */
@@ -2719,7 +2732,7 @@ static unsigned int ata_scsiop_read_cap(struct ata_device *dev, } } -return 0 ; +return 16 ; }/**
@@ -2738,7 +2751,7 @@ static unsigned int ata_scsiop_report_luns(struct ata_device *dev, { rbuf[3 ] =8 ;/* just one lun, LUN 0, size 8 bytes */ -return 0 ; +return 16 ; }/*
@@ -3463,13 +3476,13 @@ static unsigned int ata_scsiop_maint_in(struct ata_device *dev,if ((cdb[1 ] &0x1f ) !=MI_REPORT_SUPPORTED_OPERATION_CODES ) {ata_scsi_set_invalid_field (dev, cmd,1 ,0xff ); -return 1 ; +return 0 ; }if (cdb[2 ] !=1 && cdb[2 ] !=3 ) {ata_dev_warn (dev,"invalid command format %d\n" , cdb[2 ]);ata_scsi_set_invalid_field (dev, cmd,1 ,0xff ); -return 1 ; +return 0 ; }switch (cdb[3 ]) {
@@ -3542,7 +3555,7 @@ static unsigned int ata_scsiop_maint_in(struct ata_device *dev, rbuf[0 ] = rwcdlp; rbuf[1 ] = cdlp | supported; -return 0 ; +return 4 ; }/**
Signature · 1 line
2.47.0
Quoted 9 lines · Damien Le Moal
The first 5 patches of this series refactor and cleanup the libata-scsi code handling command emulation. There are no functional changes introduced by these patches.
The last patch of the series (patch 6) improves the command emulation by accurately handling the scsi command residual and transferring back to the requester only the relevant data of a command reply.
[...]
Applied to libata/linux.git (for-6.13), thanks!
[1/6] ata: libata-scsi: Refactor ata_scsi_simulate()
https://git.kernel.org/libata/linux/c/b055e3be [2/6] ata: libata-scsi: Refactor ata_scsiop_read_cap() https://git.kernel.org/libata/linux/c/44bdde15 [3/6] ata: libata-scsi: Refactor ata_scsiop_maint_in() https://git.kernel.org/libata/linux/c/4ab7bb97 [4/6] ata: libata-scsi: Document all VPD page inquiry actors https://git.kernel.org/libata/linux/c/47000e84 [5/6] ata: libata-scsi: Remove struct ata_scsi_args https://git.kernel.org/libata/linux/c/2365278e [6/6] ata: libata-scsi: Return residual for emulated SCSI commands https://git.kernel.org/libata/linux/c/5251ae22
Kind regards,
Niklas