@ -41,7 +41,10 @@ do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0)
# define SCSI_DMA_BUF_SIZE 131072
# define SCSI_MAX_INQUIRY_LEN 256
# define SCSI_REQ_STATUS_RETRY 0x01
# define SCSI_REQ_STATUS_RETRY 0x01
# define SCSI_REQ_STATUS_RETRY_TYPE_MASK 0x06
# define SCSI_REQ_STATUS_RETRY_READ 0x00
# define SCSI_REQ_STATUS_RETRY_WRITE 0x02
typedef struct SCSIDiskState SCSIDiskState ;
@ -70,6 +73,8 @@ struct SCSIDiskState
char * serial ;
} ;
static int scsi_handle_rw_error ( SCSIDiskReq * r , int error , int type ) ;
static SCSIDiskReq * scsi_new_request ( SCSIDiskState * s , uint32_t tag ,
uint32_t lun )
{
@ -127,34 +132,30 @@ static void scsi_cancel_io(SCSIDevice *d, uint32_t tag)
static void scsi_read_complete ( void * opaque , int ret )
{
SCSIDiskReq * r = ( SCSIDiskReq * ) opaque ;
int n ;
r - > req . aiocb = NULL ;
if ( ret ) {
DPRINTF ( " IO error \n " ) ;
r - > req . bus - > complete ( r - > req . bus , SCSI_REASON_DATA , r - > req . tag , 0 ) ;
scsi_command_complete ( r , CHECK_CONDITION , NO_SENSE ) ;
return ;
if ( scsi_handle_rw_error ( r , - ret , SCSI_REQ_STATUS_RETRY_READ ) ) {
return ;
}
}
DPRINTF ( " Data ready tag=0x%x len=%zd \n " , r - > req . tag , r - > iov . iov_len ) ;
n = r - > iov . iov_len / 512 ;
r - > sector + = n ;
r - > sector_count - = n ;
r - > req . bus - > complete ( r - > req . bus , SCSI_REASON_DATA , r - > req . tag , r - > iov . iov_len ) ;
}
/* Read more data from scsi device into buffer. */
static void scsi_read_data ( SCSIDevice * d , uint32_t tag )
static void scsi_read_request ( SCSIDiskReq * r )
{
SCSIDiskState * s = DO_UPCAST ( SCSIDiskState , qdev , d ) ;
SCSIDiskReq * r ;
SCSIDiskState * s = DO_UPCAST ( SCSIDiskState , qdev , r - > req . dev ) ;
uint32_t n ;
r = scsi_find_request ( s , tag ) ;
if ( ! r ) {
BADF ( " Bad read tag 0x%x \n " , tag ) ;
/* ??? This is the wrong error. */
scsi_command_complete ( r , CHECK_CONDITION , HARDWARE_ERROR ) ;
return ;
}
if ( r - > sector_count = = ( uint32_t ) - 1 ) {
DPRINTF ( " Read buf_len=%zd \n " , r - > iov . iov_len ) ;
r - > sector_count = 0 ;
@ -177,29 +178,54 @@ static void scsi_read_data(SCSIDevice *d, uint32_t tag)
scsi_read_complete , r ) ;
if ( r - > req . aiocb = = NULL )
scsi_command_complete ( r , CHECK_CONDITION , HARDWARE_ERROR ) ;
r - > sector + = n ;
r - > sector_count - = n ;
}
static int scsi_handle_write_error ( SCSIDiskReq * r , int error )
/* Read more data from scsi device into buffer. */
static void scsi_read_data ( SCSIDevice * d , uint32_t tag )
{
SCSIDiskState * s = DO_UPCAST ( SCSIDiskState , qdev , d ) ;
SCSIDiskReq * r ;
r = scsi_find_request ( s , tag ) ;
if ( ! r ) {
BADF ( " Bad read tag 0x%x \n " , tag ) ;
/* ??? This is the wrong error. */
scsi_command_complete ( r , CHECK_CONDITION , HARDWARE_ERROR ) ;
return ;
}
/* No data transfer may already be in progress */
assert ( r - > req . aiocb = = NULL ) ;
scsi_read_request ( r ) ;
}
static int scsi_handle_rw_error ( SCSIDiskReq * r , int error , int type )
{
int is_read = ( type = = SCSI_REQ_STATUS_RETRY_READ ) ;
SCSIDiskState * s = DO_UPCAST ( SCSIDiskState , qdev , r - > req . dev ) ;
BlockErrorAction action = bdrv_get_on_error ( s - > bs , 0 ) ;
BlockErrorAction action = bdrv_get_on_error ( s - > bs , is_read ) ;
if ( action = = BLOCK_ERR_IGNORE ) {
bdrv_mon_event ( s - > bs , BDRV_ACTION_IGNORE , 0 ) ;
bdrv_mon_event ( s - > bs , BDRV_ACTION_IGNORE , is_read ) ;
return 0 ;
}
if ( ( error = = ENOSPC & & action = = BLOCK_ERR_STOP_ENOSPC )
| | action = = BLOCK_ERR_STOP_ANY ) {
r - > status | = SCSI_REQ_STATUS_RETRY ;
bdrv_mon_event ( s - > bs , BDRV_ACTION_STOP , 0 ) ;
type & = SCSI_REQ_STATUS_RETRY_TYPE_MASK ;
r - > status | = SCSI_REQ_STATUS_RETRY | type ;
bdrv_mon_event ( s - > bs , BDRV_ACTION_STOP , is_read ) ;
vm_stop ( 0 ) ;
} else {
if ( type = = SCSI_REQ_STATUS_RETRY_READ ) {
r - > req . bus - > complete ( r - > req . bus , SCSI_REASON_DATA , r - > req . tag , 0 ) ;
}
scsi_command_complete ( r , CHECK_CONDITION ,
HARDWARE_ERROR ) ;
bdrv_mon_event ( s - > bs , BDRV_ACTION_REPORT , 0 ) ;
bdrv_mon_event ( s - > bs , BDRV_ACTION_REPORT , is_read ) ;
}
return 1 ;
@ -214,8 +240,9 @@ static void scsi_write_complete(void * opaque, int ret)
r - > req . aiocb = NULL ;
if ( ret ) {
if ( scsi_handle_write _error ( r , - ret ) )
if ( scsi_handle_rw _error ( r , - ret , SCSI_REQ_STATUS_RETRY_WRITE ) ) {
return ;
}
}
n = r - > iov . iov_len / 512 ;
@ -268,8 +295,8 @@ static int scsi_write_data(SCSIDevice *d, uint32_t tag)
return 1 ;
}
if ( r - > req . aiocb )
BADF ( " Data transfer already in progress \n " ) ;
/* No data transfer may already be in progress */
assert ( r - > req . aiocb = = NULL ) ;
scsi_write_request ( r ) ;
@ -288,8 +315,18 @@ static void scsi_dma_restart_bh(void *opaque)
QTAILQ_FOREACH ( req , & s - > qdev . requests , next ) {
r = DO_UPCAST ( SCSIDiskReq , req , req ) ;
if ( r - > status & SCSI_REQ_STATUS_RETRY ) {
r - > status & = ~ SCSI_REQ_STATUS_RETRY ;
scsi_write_request ( r ) ;
int status = r - > status ;
r - > status & =
~ ( SCSI_REQ_STATUS_RETRY | SCSI_REQ_STATUS_RETRY_TYPE_MASK ) ;
switch ( status & SCSI_REQ_STATUS_RETRY_TYPE_MASK ) {
case SCSI_REQ_STATUS_RETRY_READ :
scsi_read_request ( r ) ;
break ;
case SCSI_REQ_STATUS_RETRY_WRITE :
scsi_write_request ( r ) ;
break ;
}
}
}
}
@ -1152,11 +1189,6 @@ static int scsi_disk_initfn(SCSIDevice *dev)
return - 1 ;
}
if ( bdrv_get_on_error ( s - > bs , 1 ) ! = BLOCK_ERR_REPORT ) {
error_report ( " Device doesn't support drive option rerror " ) ;
return - 1 ;
}
if ( ! s - > serial ) {
/* try to fall back to value set with legacy -drive serial=... */
dinfo = drive_get_by_blockdev ( s - > bs ) ;