2005-04-17 02:20:36 +04:00
/*
2005-08-29 04:18:39 +04:00
* libata - scsi . c - helper library for ATA
*
* Maintained by : Jeff Garzik < jgarzik @ pobox . com >
* Please ALWAYS copy linux - ide @ vger . kernel . org
* on emails .
*
* Copyright 2003 - 2004 Red Hat , Inc . All rights reserved .
* Copyright 2003 - 2004 Jeff Garzik
*
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 , or ( at your option )
* any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; see the file COPYING . If not , write to
* the Free Software Foundation , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*
*
* libata documentation is available via ' make { ps | pdf } docs ' ,
* as Documentation / DocBook / libata . *
*
* Hardware documentation available from
* - http : //www.t10.org/
* - http : //www.t13.org/
*
2005-04-17 02:20:36 +04:00
*/
# include <linux/kernel.h>
# include <linux/blkdev.h>
# include <linux/spinlock.h>
# include <scsi/scsi.h>
# include <scsi/scsi_host.h>
2006-06-10 20:01:03 +04:00
# include <scsi/scsi_cmnd.h>
2005-11-12 01:38:53 +03:00
# include <scsi/scsi_eh.h>
2005-10-31 07:31:48 +03:00
# include <scsi/scsi_device.h>
2006-05-15 16:03:48 +04:00
# include <scsi/scsi_tcq.h>
2006-03-18 12:40:14 +03:00
# include <scsi/scsi_transport.h>
2005-04-17 02:20:36 +04:00
# include <linux/libata.h>
2005-05-12 23:45:22 +04:00
# include <linux/hdreg.h>
2005-04-17 02:20:36 +04:00
# include <asm/uaccess.h>
# include "libata.h"
2005-05-12 23:45:22 +04:00
# define SECTOR_SIZE 512
2006-12-17 04:45:57 +03:00
typedef unsigned int ( * ata_xlat_func_t ) ( struct ata_queued_cmd * qc ) ;
2006-05-31 13:27:34 +04:00
static struct ata_device * __ata_scsi_find_dev ( struct ata_port * ap ,
const struct scsi_device * scsidev ) ;
static struct ata_device * ata_scsi_find_dev ( struct ata_port * ap ,
const struct scsi_device * scsidev ) ;
2006-05-31 13:28:07 +04:00
static int ata_scsi_user_scan ( struct Scsi_Host * shost , unsigned int channel ,
unsigned int id , unsigned int lun ) ;
2006-05-31 13:27:34 +04:00
2005-04-17 02:20:36 +04:00
2005-10-28 23:58:28 +04:00
# define RW_RECOVERY_MPAGE 0x1
# define RW_RECOVERY_MPAGE_LEN 12
# define CACHE_MPAGE 0x8
# define CACHE_MPAGE_LEN 20
# define CONTROL_MPAGE 0xa
# define CONTROL_MPAGE_LEN 12
# define ALL_MPAGES 0x3f
# define ALL_SUB_MPAGES 0xff
static const u8 def_rw_recovery_mpage [ ] = {
RW_RECOVERY_MPAGE ,
RW_RECOVERY_MPAGE_LEN - 2 ,
( 1 < < 7 ) | /* AWRE, sat-r06 say it shall be 0 */
( 1 < < 6 ) , /* ARRE (auto read reallocation) */
0 , /* read retry count */
0 , 0 , 0 , 0 ,
0 , /* write retry count */
0 , 0 , 0
} ;
static const u8 def_cache_mpage [ CACHE_MPAGE_LEN ] = {
CACHE_MPAGE ,
CACHE_MPAGE_LEN - 2 ,
0 , /* contains WCE, needs to be 0 for logic */
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
0 , /* contains DRA, needs to be 0 for logic */
0 , 0 , 0 , 0 , 0 , 0 , 0
} ;
static const u8 def_control_mpage [ CONTROL_MPAGE_LEN ] = {
CONTROL_MPAGE ,
CONTROL_MPAGE_LEN - 2 ,
2 , /* DSENSE=0, GLTSD=1 */
0 , /* [QAM+QERR may be 1, see 05-359r1] */
0 , 0 , 0 , 0 , 0xff , 0xff ,
0 , 30 /* extended self test time, see 05-359r1 */
} ;
2006-03-18 12:40:14 +03:00
/*
* libata transport template . libata doesn ' t do real transport stuff .
* It just needs the eh_timed_out hook .
*/
struct scsi_transport_template ata_scsi_transport_template = {
2006-04-01 21:21:04 +04:00
. eh_strategy_handler = ata_scsi_error ,
2006-03-18 12:40:14 +03:00
. eh_timed_out = ata_scsi_timed_out ,
2006-05-31 13:28:09 +04:00
. user_scan = ata_scsi_user_scan ,
2006-03-18 12:40:14 +03:00
} ;
2005-04-17 02:20:36 +04:00
2005-10-09 17:09:35 +04:00
static void ata_scsi_invalid_field ( struct scsi_cmnd * cmd ,
void ( * done ) ( struct scsi_cmnd * ) )
{
ata_scsi_set_sense ( cmd , ILLEGAL_REQUEST , 0x24 , 0x0 ) ;
/* "Invalid field in cbd" */
done ( cmd ) ;
}
2005-04-17 02:20:36 +04:00
/**
* ata_std_bios_param - generic bios head / sector / cylinder calculator used by sd .
* @ sdev : SCSI device for which BIOS geometry is to be determined
* @ bdev : block device associated with @ sdev
* @ capacity : capacity of SCSI device
* @ geom : location to which geometry will be output
*
* Generic bios head / sector / cylinder calculator
* used by sd . Most BIOSes nowadays expect a XXX / 255 / 16 ( CHS )
* mapping . Some situations may arise where the disk is not
* bootable if this is not used .
*
* LOCKING :
* Defined by the SCSI layer . We don ' t really care .
*
* RETURNS :
* Zero .
*/
int ata_std_bios_param ( struct scsi_device * sdev , struct block_device * bdev ,
sector_t capacity , int geom [ ] )
{
geom [ 0 ] = 255 ;
geom [ 1 ] = 63 ;
sector_div ( capacity , 255 * 63 ) ;
geom [ 2 ] = capacity ;
return 0 ;
}
2007-01-02 14:20:07 +03:00
/**
* ata_get_identity - Handler for HDIO_GET_IDENTITY ioctl
* @ sdev : SCSI device to get identify data for
* @ arg : User buffer area for identify data
*
* LOCKING :
* Defined by the SCSI layer . We don ' t really care .
*
* RETURNS :
* Zero on success , negative errno on error .
*/
static int ata_get_identity ( struct scsi_device * sdev , void __user * arg )
{
struct ata_port * ap = ata_shost_to_port ( sdev - > host ) ;
struct ata_device * dev = ata_scsi_find_dev ( ap , sdev ) ;
u16 __user * dst = arg ;
char buf [ 40 ] ;
if ( ! dev )
return - ENOMSG ;
if ( copy_to_user ( dst , dev - > id , ATA_ID_WORDS * sizeof ( u16 ) ) )
return - EFAULT ;
ata_id_string ( dev - > id , buf , ATA_ID_PROD , ATA_ID_PROD_LEN ) ;
if ( copy_to_user ( dst + ATA_ID_PROD , buf , ATA_ID_PROD_LEN ) )
return - EFAULT ;
ata_id_string ( dev - > id , buf , ATA_ID_FW_REV , ATA_ID_FW_REV_LEN ) ;
if ( copy_to_user ( dst + ATA_ID_FW_REV , buf , ATA_ID_FW_REV_LEN ) )
return - EFAULT ;
ata_id_string ( dev - > id , buf , ATA_ID_SERNO , ATA_ID_SERNO_LEN ) ;
if ( copy_to_user ( dst + ATA_ID_SERNO , buf , ATA_ID_SERNO_LEN ) )
return - EFAULT ;
return 0 ;
}
2005-05-12 23:45:22 +04:00
/**
* ata_cmd_ioctl - Handler for HDIO_DRIVE_CMD ioctl
2005-11-02 08:29:27 +03:00
* @ scsidev : Device to which we are issuing command
2005-05-12 23:45:22 +04:00
* @ arg : User provided data for issuing command
*
* LOCKING :
* Defined by the SCSI layer . We don ' t really care .
*
* RETURNS :
* Zero on success , negative errno on error .
*/
int ata_cmd_ioctl ( struct scsi_device * scsidev , void __user * arg )
{
int rc = 0 ;
u8 scsi_cmd [ MAX_COMMAND_SIZE ] ;
2006-10-11 01:29:25 +04:00
u8 args [ 4 ] , * argbuf = NULL , * sensebuf = NULL ;
2005-05-12 23:45:22 +04:00
int argsize = 0 ;
2005-11-12 01:38:53 +03:00
enum dma_data_direction data_dir ;
2006-10-11 01:29:25 +04:00
int cmd_result ;
2005-05-12 23:45:22 +04:00
2006-01-28 21:15:32 +03:00
if ( arg = = NULL )
2005-05-12 23:45:22 +04:00
return - EINVAL ;
if ( copy_from_user ( args , arg , sizeof ( args ) ) )
return - EFAULT ;
2006-10-11 01:29:25 +04:00
sensebuf = kzalloc ( SCSI_SENSE_BUFFERSIZE , GFP_NOIO ) ;
if ( ! sensebuf )
return - ENOMEM ;
2005-05-12 23:45:22 +04:00
memset ( scsi_cmd , 0 , sizeof ( scsi_cmd ) ) ;
if ( args [ 3 ] ) {
argsize = SECTOR_SIZE * args [ 3 ] ;
argbuf = kmalloc ( argsize , GFP_KERNEL ) ;
2005-10-04 18:21:19 +04:00
if ( argbuf = = NULL ) {
rc = - ENOMEM ;
goto error ;
}
2005-05-12 23:45:22 +04:00
scsi_cmd [ 1 ] = ( 4 < < 1 ) ; /* PIO Data-in */
scsi_cmd [ 2 ] = 0x0e ; /* no off.line or cc, read from dev,
block count in sector count field */
2005-11-12 01:38:53 +03:00
data_dir = DMA_FROM_DEVICE ;
2005-05-12 23:45:22 +04:00
} else {
scsi_cmd [ 1 ] = ( 3 < < 1 ) ; /* Non-data */
2006-10-11 01:29:25 +04:00
scsi_cmd [ 2 ] = 0x20 ; /* cc but no off.line or data xfer */
2005-11-12 01:38:53 +03:00
data_dir = DMA_NONE ;
2005-05-12 23:45:22 +04:00
}
scsi_cmd [ 0 ] = ATA_16 ;
scsi_cmd [ 4 ] = args [ 2 ] ;
if ( args [ 0 ] = = WIN_SMART ) { /* hack -- ide driver does this too... */
scsi_cmd [ 6 ] = args [ 3 ] ;
scsi_cmd [ 8 ] = args [ 1 ] ;
scsi_cmd [ 10 ] = 0x4f ;
scsi_cmd [ 12 ] = 0xc2 ;
} else {
scsi_cmd [ 6 ] = args [ 1 ] ;
}
scsi_cmd [ 14 ] = args [ 0 ] ;
/* Good values for timeout and retries? Values below
from scsi_ioctl_send_command ( ) for default case . . . */
2006-10-11 01:29:25 +04:00
cmd_result = scsi_execute ( scsidev , scsi_cmd , data_dir , argbuf , argsize ,
sensebuf , ( 10 * HZ ) , 5 , 0 ) ;
if ( driver_byte ( cmd_result ) = = DRIVER_SENSE ) { /* sense data available */
u8 * desc = sensebuf + 8 ;
cmd_result & = ~ ( 0xFF < < 24 ) ; /* DRIVER_SENSE is not an error */
/* If we set cc then ATA pass-through will cause a
* check condition even if no error . Filter that . */
if ( cmd_result & SAM_STAT_CHECK_CONDITION ) {
struct scsi_sense_hdr sshdr ;
scsi_normalize_sense ( sensebuf , SCSI_SENSE_BUFFERSIZE ,
& sshdr ) ;
if ( sshdr . sense_key = = 0 & &
sshdr . asc = = 0 & & sshdr . ascq = = 0 )
cmd_result & = ~ SAM_STAT_CHECK_CONDITION ;
}
/* Send userspace a few ATA registers (same as drivers/ide) */
if ( sensebuf [ 0 ] = = 0x72 & & /* format is "descriptor" */
desc [ 0 ] = = 0x09 ) { /* code is "ATA Descriptor" */
args [ 0 ] = desc [ 13 ] ; /* status */
args [ 1 ] = desc [ 3 ] ; /* error */
args [ 2 ] = desc [ 5 ] ; /* sector count (0:7) */
if ( copy_to_user ( arg , args , sizeof ( args ) ) )
rc = - EFAULT ;
}
}
if ( cmd_result ) {
2005-05-12 23:45:22 +04:00
rc = - EIO ;
goto error ;
}
if ( ( argbuf )
2006-01-28 21:15:32 +03:00
& & copy_to_user ( arg + sizeof ( args ) , argbuf , argsize ) )
2005-05-12 23:45:22 +04:00
rc = - EFAULT ;
error :
2006-10-11 01:29:25 +04:00
kfree ( sensebuf ) ;
2006-06-27 13:55:06 +04:00
kfree ( argbuf ) ;
2005-05-12 23:45:22 +04:00
return rc ;
}
/**
* ata_task_ioctl - Handler for HDIO_DRIVE_TASK ioctl
2005-11-02 08:29:27 +03:00
* @ scsidev : Device to which we are issuing command
2005-05-12 23:45:22 +04:00
* @ arg : User provided data for issuing command
*
* LOCKING :
* Defined by the SCSI layer . We don ' t really care .
*
* RETURNS :
* Zero on success , negative errno on error .
*/
int ata_task_ioctl ( struct scsi_device * scsidev , void __user * arg )
{
int rc = 0 ;
u8 scsi_cmd [ MAX_COMMAND_SIZE ] ;
2007-01-30 11:59:15 +03:00
u8 args [ 7 ] , * sensebuf = NULL ;
int cmd_result ;
2005-05-12 23:45:22 +04:00
2006-01-28 21:15:32 +03:00
if ( arg = = NULL )
2005-05-12 23:45:22 +04:00
return - EINVAL ;
if ( copy_from_user ( args , arg , sizeof ( args ) ) )
return - EFAULT ;
2007-01-30 11:59:15 +03:00
sensebuf = kzalloc ( SCSI_SENSE_BUFFERSIZE , GFP_NOIO ) ;
if ( ! sensebuf )
return - ENOMEM ;
2005-05-12 23:45:22 +04:00
memset ( scsi_cmd , 0 , sizeof ( scsi_cmd ) ) ;
scsi_cmd [ 0 ] = ATA_16 ;
scsi_cmd [ 1 ] = ( 3 < < 1 ) ; /* Non-data */
2007-01-30 11:59:15 +03:00
scsi_cmd [ 2 ] = 0x20 ; /* cc but no off.line or data xfer */
2005-05-12 23:45:22 +04:00
scsi_cmd [ 4 ] = args [ 1 ] ;
scsi_cmd [ 6 ] = args [ 2 ] ;
scsi_cmd [ 8 ] = args [ 3 ] ;
scsi_cmd [ 10 ] = args [ 4 ] ;
scsi_cmd [ 12 ] = args [ 5 ] ;
2007-03-31 01:45:52 +04:00
scsi_cmd [ 13 ] = args [ 6 ] & 0x4f ;
2005-05-12 23:45:22 +04:00
scsi_cmd [ 14 ] = args [ 0 ] ;
/* Good values for timeout and retries? Values below
2006-03-24 17:56:57 +03:00
from scsi_ioctl_send_command ( ) for default case . . . */
2007-01-30 11:59:15 +03:00
cmd_result = scsi_execute ( scsidev , scsi_cmd , DMA_NONE , NULL , 0 ,
sensebuf , ( 10 * HZ ) , 5 , 0 ) ;
if ( driver_byte ( cmd_result ) = = DRIVER_SENSE ) { /* sense data available */
u8 * desc = sensebuf + 8 ;
cmd_result & = ~ ( 0xFF < < 24 ) ; /* DRIVER_SENSE is not an error */
/* If we set cc then ATA pass-through will cause a
* check condition even if no error . Filter that . */
if ( cmd_result & SAM_STAT_CHECK_CONDITION ) {
struct scsi_sense_hdr sshdr ;
scsi_normalize_sense ( sensebuf , SCSI_SENSE_BUFFERSIZE ,
& sshdr ) ;
if ( sshdr . sense_key = = 0 & &
sshdr . asc = = 0 & & sshdr . ascq = = 0 )
cmd_result & = ~ SAM_STAT_CHECK_CONDITION ;
}
/* Send userspace ATA registers */
if ( sensebuf [ 0 ] = = 0x72 & & /* format is "descriptor" */
desc [ 0 ] = = 0x09 ) { /* code is "ATA Descriptor" */
args [ 0 ] = desc [ 13 ] ; /* status */
args [ 1 ] = desc [ 3 ] ; /* error */
args [ 2 ] = desc [ 5 ] ; /* sector count (0:7) */
args [ 3 ] = desc [ 7 ] ; /* lbal */
args [ 4 ] = desc [ 9 ] ; /* lbam */
args [ 5 ] = desc [ 11 ] ; /* lbah */
args [ 6 ] = desc [ 12 ] ; /* select */
if ( copy_to_user ( arg , args , sizeof ( args ) ) )
rc = - EFAULT ;
}
}
if ( cmd_result ) {
2005-05-12 23:45:22 +04:00
rc = - EIO ;
2007-01-30 11:59:15 +03:00
goto error ;
}
2005-05-12 23:45:22 +04:00
2007-01-30 11:59:15 +03:00
error :
kfree ( sensebuf ) ;
2005-05-12 23:45:22 +04:00
return rc ;
}
2005-04-17 02:20:36 +04:00
int ata_scsi_ioctl ( struct scsi_device * scsidev , int cmd , void __user * arg )
{
int val = - EINVAL , rc = - EINVAL ;
switch ( cmd ) {
case ATA_IOC_GET_IO32 :
val = 0 ;
if ( copy_to_user ( arg , & val , 1 ) )
return - EFAULT ;
return 0 ;
case ATA_IOC_SET_IO32 :
val = ( unsigned long ) arg ;
if ( val ! = 0 )
return - EINVAL ;
return 0 ;
2007-01-02 14:20:07 +03:00
case HDIO_GET_IDENTITY :
return ata_get_identity ( scsidev , arg ) ;
2005-05-12 23:45:22 +04:00
case HDIO_DRIVE_CMD :
if ( ! capable ( CAP_SYS_ADMIN ) | | ! capable ( CAP_SYS_RAWIO ) )
return - EACCES ;
return ata_cmd_ioctl ( scsidev , arg ) ;
case HDIO_DRIVE_TASK :
if ( ! capable ( CAP_SYS_ADMIN ) | | ! capable ( CAP_SYS_RAWIO ) )
return - EACCES ;
return ata_task_ioctl ( scsidev , arg ) ;
2005-04-17 02:20:36 +04:00
default :
rc = - ENOTTY ;
break ;
}
return rc ;
}
/**
* ata_scsi_qc_new - acquire new ata_queued_cmd reference
* @ dev : ATA device to which the new command is attached
* @ cmd : SCSI command that originated this ATA command
* @ done : SCSI command completion function
*
* Obtain a reference to an unused ata_queued_cmd structure ,
* which is the basic libata structure representing a single
* ATA command sent to the hardware .
*
* If a command was available , fill in the SCSI - specific
* portions of the structure with information on the
* current command .
*
* LOCKING :
2006-08-24 11:19:22 +04:00
* spin_lock_irqsave ( host lock )
2005-04-17 02:20:36 +04:00
*
* RETURNS :
* Command allocated , or % NULL if none available .
*/
2007-01-04 02:09:36 +03:00
static struct ata_queued_cmd * ata_scsi_qc_new ( struct ata_device * dev ,
struct scsi_cmnd * cmd ,
void ( * done ) ( struct scsi_cmnd * ) )
2005-04-17 02:20:36 +04:00
{
struct ata_queued_cmd * qc ;
2006-05-15 15:57:53 +04:00
qc = ata_qc_new_init ( dev ) ;
2005-04-17 02:20:36 +04:00
if ( qc ) {
qc - > scsicmd = cmd ;
qc - > scsidone = done ;
if ( cmd - > use_sg ) {
2005-10-05 15:13:30 +04:00
qc - > __sg = ( struct scatterlist * ) cmd - > request_buffer ;
2005-04-17 02:20:36 +04:00
qc - > n_elem = cmd - > use_sg ;
2007-01-17 21:32:12 +03:00
} else if ( cmd - > request_bufflen ) {
2005-10-05 15:13:30 +04:00
qc - > __sg = & qc - > sgent ;
2005-04-17 02:20:36 +04:00
qc - > n_elem = 1 ;
}
} else {
cmd - > result = ( DID_OK < < 16 ) | ( QUEUE_FULL < < 1 ) ;
done ( cmd ) ;
}
return qc ;
}
2005-05-12 23:45:22 +04:00
/**
* ata_dump_status - user friendly display of error info
* @ id : id of the port in question
* @ tf : ptr to filled out taskfile
*
* Decode and dump the ATA error / status registers for the user so
* that they have some idea what really happened at the non
* make - believe layer .
*
* LOCKING :
* inherited from caller
*/
2007-01-04 02:09:36 +03:00
static void ata_dump_status ( unsigned id , struct ata_taskfile * tf )
2005-05-12 23:45:22 +04:00
{
u8 stat = tf - > command , err = tf - > feature ;
printk ( KERN_WARNING " ata%u: status=0x%02x { " , id , stat ) ;
if ( stat & ATA_BUSY ) {
printk ( " Busy } \n " ) ; /* Data is not valid in this case */
} else {
if ( stat & 0x40 ) printk ( " DriveReady " ) ;
if ( stat & 0x20 ) printk ( " DeviceFault " ) ;
if ( stat & 0x10 ) printk ( " SeekComplete " ) ;
if ( stat & 0x08 ) printk ( " DataRequest " ) ;
if ( stat & 0x04 ) printk ( " CorrectedError " ) ;
if ( stat & 0x02 ) printk ( " Index " ) ;
if ( stat & 0x01 ) printk ( " Error " ) ;
printk ( " } \n " ) ;
if ( err ) {
printk ( KERN_WARNING " ata%u: error=0x%02x { " , id , err ) ;
if ( err & 0x04 ) printk ( " DriveStatusError " ) ;
if ( err & 0x80 ) {
if ( err & 0x04 ) printk ( " BadCRC " ) ;
else printk ( " Sector " ) ;
}
if ( err & 0x40 ) printk ( " UncorrectableError " ) ;
if ( err & 0x10 ) printk ( " SectorIdNotFound " ) ;
if ( err & 0x02 ) printk ( " TrackZeroNotFound " ) ;
if ( err & 0x01 ) printk ( " AddrMarkNotFound " ) ;
printk ( " } \n " ) ;
}
}
}
2007-03-02 11:32:47 +03:00
# ifdef CONFIG_PM
2006-07-03 11:07:26 +04:00
/**
* ata_scsi_device_suspend - suspend ATA device associated with sdev
* @ sdev : the SCSI device to suspend
2006-07-26 11:58:33 +04:00
* @ mesg : target power management message
2006-07-03 11:07:26 +04:00
*
* Request suspend EH action on the ATA device associated with
* @ sdev and wait for the operation to complete .
*
* LOCKING :
* Kernel thread context ( may sleep ) .
*
* RETURNS :
* 0 on success , - errno otherwise .
*/
2006-07-26 11:58:33 +04:00
int ata_scsi_device_suspend ( struct scsi_device * sdev , pm_message_t mesg )
2006-01-06 11:28:07 +03:00
{
2006-04-11 21:12:34 +04:00
struct ata_port * ap = ata_shost_to_port ( sdev - > host ) ;
2006-07-03 11:07:26 +04:00
struct ata_device * dev = ata_scsi_find_dev ( ap , sdev ) ;
unsigned long flags ;
unsigned int action ;
int rc = 0 ;
if ( ! dev )
goto out ;
spin_lock_irqsave ( ap - > lock , flags ) ;
/* wait for the previous resume to complete */
while ( dev - > flags & ATA_DFLAG_SUSPENDED ) {
spin_unlock_irqrestore ( ap - > lock , flags ) ;
ata_port_wait_eh ( ap ) ;
spin_lock_irqsave ( ap - > lock , flags ) ;
}
/* if @sdev is already detached, nothing to do */
if ( sdev - > sdev_state = = SDEV_OFFLINE | |
sdev - > sdev_state = = SDEV_CANCEL | | sdev - > sdev_state = = SDEV_DEL )
goto out_unlock ;
/* request suspend */
action = ATA_EH_SUSPEND ;
2006-07-26 11:58:33 +04:00
if ( mesg . event ! = PM_EVENT_SUSPEND )
2006-07-03 11:07:26 +04:00
action | = ATA_EH_PM_FREEZE ;
ap - > eh_info . dev_action [ dev - > devno ] | = action ;
ap - > eh_info . flags | = ATA_EHI_QUIET ;
ata_port_schedule_eh ( ap ) ;
spin_unlock_irqrestore ( ap - > lock , flags ) ;
2006-01-06 11:28:07 +03:00
2006-07-03 11:07:26 +04:00
/* wait for EH to do the job */
ata_port_wait_eh ( ap ) ;
spin_lock_irqsave ( ap - > lock , flags ) ;
/* If @sdev is still attached but the associated ATA device
* isn ' t suspended , the operation failed .
*/
if ( sdev - > sdev_state ! = SDEV_OFFLINE & &
sdev - > sdev_state ! = SDEV_CANCEL & & sdev - > sdev_state ! = SDEV_DEL & &
! ( dev - > flags & ATA_DFLAG_SUSPENDED ) )
rc = - EIO ;
out_unlock :
spin_unlock_irqrestore ( ap - > lock , flags ) ;
out :
if ( rc = = 0 )
2006-07-26 11:58:33 +04:00
sdev - > sdev_gendev . power . power_state = mesg ;
2006-07-03 11:07:26 +04:00
return rc ;
2006-01-06 11:28:07 +03:00
}
2006-07-03 11:07:26 +04:00
/**
* ata_scsi_device_resume - resume ATA device associated with sdev
* @ sdev : the SCSI device to resume
*
* Request resume EH action on the ATA device associated with
* @ sdev and return immediately . This enables parallel
* wakeup / spinup of devices .
*
* LOCKING :
* Kernel thread context ( may sleep ) .
*
* RETURNS :
* 0.
*/
int ata_scsi_device_resume ( struct scsi_device * sdev )
2006-01-06 11:28:07 +03:00
{
2006-04-11 21:12:34 +04:00
struct ata_port * ap = ata_shost_to_port ( sdev - > host ) ;
2006-07-03 11:07:26 +04:00
struct ata_device * dev = ata_scsi_find_dev ( ap , sdev ) ;
struct ata_eh_info * ehi = & ap - > eh_info ;
unsigned long flags ;
unsigned int action ;
if ( ! dev )
goto out ;
spin_lock_irqsave ( ap - > lock , flags ) ;
/* if @sdev is already detached, nothing to do */
if ( sdev - > sdev_state = = SDEV_OFFLINE | |
sdev - > sdev_state = = SDEV_CANCEL | | sdev - > sdev_state = = SDEV_DEL )
goto out_unlock ;
/* request resume */
action = ATA_EH_RESUME ;
if ( sdev - > sdev_gendev . power . power_state . event = = PM_EVENT_SUSPEND )
__ata_ehi_hotplugged ( ehi ) ;
else
action | = ATA_EH_PM_FREEZE | ATA_EH_SOFTRESET ;
ehi - > dev_action [ dev - > devno ] | = action ;
/* We don't want autopsy and verbose EH messages. Disable
* those if we ' re the only device on this link .
*/
if ( ata_port_max_devices ( ap ) = = 1 )
ehi - > flags | = ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET ;
ata_port_schedule_eh ( ap ) ;
out_unlock :
spin_unlock_irqrestore ( ap - > lock , flags ) ;
out :
sdev - > sdev_gendev . power . power_state = PMSG_ON ;
return 0 ;
2006-01-06 11:28:07 +03:00
}
2007-03-02 11:32:47 +03:00
# endif /* CONFIG_PM */
2006-01-06 11:28:07 +03:00
2005-04-17 02:20:36 +04:00
/**
* ata_to_sense_error - convert ATA error to SCSI error
2005-11-02 08:29:27 +03:00
* @ id : ATA device number
2005-04-17 02:20:36 +04:00
* @ drv_stat : value contained in ATA status register
2005-05-12 23:45:22 +04:00
* @ drv_err : value contained in ATA error register
* @ sk : the sense key we ' ll fill out
* @ asc : the additional sense code we ' ll fill out
* @ ascq : the additional sense code qualifier we ' ll fill out
2006-05-15 15:58:16 +04:00
* @ verbose : be verbose
2005-04-17 02:20:36 +04:00
*
2005-05-12 23:45:22 +04:00
* Converts an ATA error into a SCSI error . Fill out pointers to
* SK , ASC , and ASCQ bytes for later use in fixed or descriptor
* format sense blocks .
2005-04-17 02:20:36 +04:00
*
* LOCKING :
2006-08-24 11:19:22 +04:00
* spin_lock_irqsave ( host lock )
2005-04-17 02:20:36 +04:00
*/
2007-01-04 02:09:36 +03:00
static void ata_to_sense_error ( unsigned id , u8 drv_stat , u8 drv_err , u8 * sk ,
u8 * asc , u8 * ascq , int verbose )
2005-04-17 02:20:36 +04:00
{
2005-05-12 23:45:22 +04:00
int i ;
2005-10-09 18:40:44 +04:00
2005-04-17 02:20:36 +04:00
/* Based on the 3ware driver translation table */
2005-11-28 12:06:23 +03:00
static const unsigned char sense_table [ ] [ 4 ] = {
2005-04-17 02:20:36 +04:00
/* BBD|ECC|ID|MAR */
{ 0xd1 , ABORTED_COMMAND , 0x00 , 0x00 } , // Device busy Aborted command
/* BBD|ECC|ID */
{ 0xd0 , ABORTED_COMMAND , 0x00 , 0x00 } , // Device busy Aborted command
/* ECC|MC|MARK */
{ 0x61 , HARDWARE_ERROR , 0x00 , 0x00 } , // Device fault Hardware error
/* ICRC|ABRT */ /* NB: ICRC & !ABRT is BBD */
{ 0x84 , ABORTED_COMMAND , 0x47 , 0x00 } , // Data CRC error SCSI parity error
/* MC|ID|ABRT|TRK0|MARK */
{ 0x37 , NOT_READY , 0x04 , 0x00 } , // Unit offline Not ready
/* MCR|MARK */
{ 0x09 , NOT_READY , 0x04 , 0x00 } , // Unrecovered disk error Not ready
/* Bad address mark */
{ 0x01 , MEDIUM_ERROR , 0x13 , 0x00 } , // Address mark not found Address mark not found for data field
/* TRK0 */
{ 0x02 , HARDWARE_ERROR , 0x00 , 0x00 } , // Track 0 not found Hardware error
/* Abort & !ICRC */
{ 0x04 , ABORTED_COMMAND , 0x00 , 0x00 } , // Aborted command Aborted command
/* Media change request */
{ 0x08 , NOT_READY , 0x04 , 0x00 } , // Media change request FIXME: faking offline
/* SRV */
{ 0x10 , ABORTED_COMMAND , 0x14 , 0x00 } , // ID not found Recorded entity not found
/* Media change */
{ 0x08 , NOT_READY , 0x04 , 0x00 } , // Media change FIXME: faking offline
/* ECC */
{ 0x40 , MEDIUM_ERROR , 0x11 , 0x04 } , // Uncorrectable ECC error Unrecovered read error
/* BBD - block marked bad */
{ 0x80 , MEDIUM_ERROR , 0x11 , 0x04 } , // Block marked bad Medium error, unrecovered read error
{ 0xFF , 0xFF , 0xFF , 0xFF } , // END mark
} ;
2005-11-28 12:06:23 +03:00
static const unsigned char stat_table [ ] [ 4 ] = {
2005-04-17 02:20:36 +04:00
/* Must be first because BUSY means no other bits valid */
{ 0x80 , ABORTED_COMMAND , 0x47 , 0x00 } , // Busy, fake parity for now
{ 0x20 , HARDWARE_ERROR , 0x00 , 0x00 } , // Device fault
{ 0x08 , ABORTED_COMMAND , 0x47 , 0x00 } , // Timed out in xfer, fake parity for now
{ 0x04 , RECOVERED_ERROR , 0x11 , 0x00 } , // Recovered ECC error Medium error, recovered
{ 0xFF , 0xFF , 0xFF , 0xFF } , // END mark
} ;
/*
* Is this an error we can process / parse
*/
2005-05-12 23:45:22 +04:00
if ( drv_stat & ATA_BUSY ) {
drv_err = 0 ; /* Ignore the err bits, they're invalid */
2005-04-17 02:20:36 +04:00
}
2005-05-12 23:45:22 +04:00
if ( drv_err ) {
/* Look for drv_err */
for ( i = 0 ; sense_table [ i ] [ 0 ] ! = 0xFF ; i + + ) {
/* Look for best matches first */
2006-03-24 17:56:57 +03:00
if ( ( sense_table [ i ] [ 0 ] & drv_err ) = =
2005-05-12 23:45:22 +04:00
sense_table [ i ] [ 0 ] ) {
* sk = sense_table [ i ] [ 1 ] ;
* asc = sense_table [ i ] [ 2 ] ;
* ascq = sense_table [ i ] [ 3 ] ;
goto translate_done ;
}
}
/* No immediate match */
2006-05-15 15:58:16 +04:00
if ( verbose )
printk ( KERN_WARNING " ata%u: no sense translation for "
" error 0x%02x \n " , id , drv_err ) ;
2005-04-17 02:20:36 +04:00
}
2005-05-12 23:45:22 +04:00
/* Fall back to interpreting status bits */
for ( i = 0 ; stat_table [ i ] [ 0 ] ! = 0xFF ; i + + ) {
if ( stat_table [ i ] [ 0 ] & drv_stat ) {
* sk = stat_table [ i ] [ 1 ] ;
* asc = stat_table [ i ] [ 2 ] ;
* ascq = stat_table [ i ] [ 3 ] ;
goto translate_done ;
2005-04-17 02:20:36 +04:00
}
2005-05-12 23:45:22 +04:00
}
/* No error? Undecoded? */
2006-05-15 15:58:16 +04:00
if ( verbose )
printk ( KERN_WARNING " ata%u: no sense translation for "
" status: 0x%02x \n " , id , drv_stat ) ;
2005-05-12 23:45:22 +04:00
2006-03-21 18:53:46 +03:00
/* We need a sensible error return here, which is tricky, and one
that won ' t cause people to do things like return a disk wrongly */
* sk = ABORTED_COMMAND ;
* asc = 0x00 ;
* ascq = 0x00 ;
2005-05-12 23:45:22 +04:00
translate_done :
2006-05-15 15:58:16 +04:00
if ( verbose )
printk ( KERN_ERR " ata%u: translated ATA stat/err 0x%02x/%02x "
" to SCSI SK/ASC/ASCQ 0x%x/%02x/%02x \n " ,
id , drv_stat , drv_err , * sk , * asc , * ascq ) ;
2005-05-12 23:45:22 +04:00
return ;
}
/*
2006-11-14 16:37:35 +03:00
* ata_gen_passthru_sense - Generate check condition sense block .
2005-05-12 23:45:22 +04:00
* @ qc : Command that completed .
*
* This function is specific to the ATA descriptor format sense
* block specified for the ATA pass through commands . Regardless
* of whether the command errored or not , return a sense
* block . Copy all controller registers into the sense
* block . Clear sense key , ASC & ASCQ if there is no error .
*
* LOCKING :
2006-11-14 16:37:35 +03:00
* None .
2005-05-12 23:45:22 +04:00
*/
2006-11-14 16:37:35 +03:00
static void ata_gen_passthru_sense ( struct ata_queued_cmd * qc )
2005-05-12 23:45:22 +04:00
{
struct scsi_cmnd * cmd = qc - > scsicmd ;
2006-05-15 15:57:40 +04:00
struct ata_taskfile * tf = & qc - > result_tf ;
2005-05-12 23:45:22 +04:00
unsigned char * sb = cmd - > sense_buffer ;
unsigned char * desc = sb + 8 ;
2006-05-15 15:58:16 +04:00
int verbose = qc - > ap - > ops - > error_handler = = NULL ;
2005-05-12 23:45:22 +04:00
memset ( sb , 0 , SCSI_SENSE_BUFFERSIZE ) ;
2005-10-06 17:40:20 +04:00
cmd - > result = ( DRIVER_SENSE < < 24 ) | SAM_STAT_CHECK_CONDITION ;
2005-05-12 23:45:22 +04:00
/*
* Use ata_to_sense_error ( ) to map status register bits
* onto sense key , asc & ascq .
*/
2006-04-02 13:51:53 +04:00
if ( qc - > err_mask | |
tf - > command & ( ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ ) ) {
2007-02-20 19:06:51 +03:00
ata_to_sense_error ( qc - > ap - > print_id , tf - > command , tf - > feature ,
2006-05-15 15:58:16 +04:00
& sb [ 1 ] , & sb [ 2 ] , & sb [ 3 ] , verbose ) ;
2005-05-12 23:45:22 +04:00
sb [ 1 ] & = 0x0f ;
2005-04-17 02:20:36 +04:00
}
2005-05-12 23:45:22 +04:00
/*
* Sense data is current and format is descriptor .
*/
sb [ 0 ] = 0x72 ;
2005-04-17 02:20:36 +04:00
2005-05-12 23:45:22 +04:00
desc [ 0 ] = 0x09 ;
2006-11-14 16:37:35 +03:00
/* set length of additional sense data */
sb [ 7 ] = 14 ;
desc [ 1 ] = 12 ;
2005-05-12 23:45:22 +04:00
/*
* Copy registers into sense buffer .
*/
desc [ 2 ] = 0x00 ;
desc [ 3 ] = tf - > feature ; /* == error reg */
desc [ 5 ] = tf - > nsect ;
desc [ 7 ] = tf - > lbal ;
desc [ 9 ] = tf - > lbam ;
desc [ 11 ] = tf - > lbah ;
desc [ 12 ] = tf - > device ;
desc [ 13 ] = tf - > command ; /* == status reg */
/*
* Fill in Extend bit , and the high order bytes
* if applicable .
*/
if ( tf - > flags & ATA_TFLAG_LBA48 ) {
desc [ 2 ] | = 0x01 ;
desc [ 4 ] = tf - > hob_nsect ;
desc [ 6 ] = tf - > hob_lbal ;
desc [ 8 ] = tf - > hob_lbam ;
desc [ 10 ] = tf - > hob_lbah ;
2005-04-17 02:20:36 +04:00
}
2005-05-12 23:45:22 +04:00
}
2005-04-17 02:20:36 +04:00
2005-05-12 23:45:22 +04:00
/**
2006-11-14 16:37:35 +03:00
* ata_gen_ata_sense - generate a SCSI fixed sense block
2005-05-12 23:45:22 +04:00
* @ qc : Command that we are erroring out
*
2006-11-14 16:37:35 +03:00
* Generate sense block for a failed ATA command @ qc . Descriptor
* format is used to accomodate LBA48 block address .
2005-05-12 23:45:22 +04:00
*
* LOCKING :
2006-11-14 16:37:35 +03:00
* None .
2005-05-12 23:45:22 +04:00
*/
2006-11-14 16:37:35 +03:00
static void ata_gen_ata_sense ( struct ata_queued_cmd * qc )
2005-05-12 23:45:22 +04:00
{
2006-11-14 16:37:35 +03:00
struct ata_device * dev = qc - > dev ;
2005-05-12 23:45:22 +04:00
struct scsi_cmnd * cmd = qc - > scsicmd ;
2006-05-15 15:57:40 +04:00
struct ata_taskfile * tf = & qc - > result_tf ;
2005-05-12 23:45:22 +04:00
unsigned char * sb = cmd - > sense_buffer ;
2006-11-14 16:37:35 +03:00
unsigned char * desc = sb + 8 ;
2006-05-15 15:58:16 +04:00
int verbose = qc - > ap - > ops - > error_handler = = NULL ;
2006-11-14 16:37:35 +03:00
u64 block ;
2005-05-12 23:45:22 +04:00
memset ( sb , 0 , SCSI_SENSE_BUFFERSIZE ) ;
2005-10-06 17:40:20 +04:00
cmd - > result = ( DRIVER_SENSE < < 24 ) | SAM_STAT_CHECK_CONDITION ;
2005-05-12 23:45:22 +04:00
2006-11-14 16:37:35 +03:00
/* sense data is current and format is descriptor */
sb [ 0 ] = 0x72 ;
/* Use ata_to_sense_error() to map status register bits
2005-05-12 23:45:22 +04:00
* onto sense key , asc & ascq .
*/
2006-04-02 13:51:53 +04:00
if ( qc - > err_mask | |
tf - > command & ( ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ ) ) {
2007-02-20 19:06:51 +03:00
ata_to_sense_error ( qc - > ap - > print_id , tf - > command , tf - > feature ,
2006-11-14 16:37:35 +03:00
& sb [ 1 ] , & sb [ 2 ] , & sb [ 3 ] , verbose ) ;
sb [ 1 ] & = 0x0f ;
2005-04-17 02:20:36 +04:00
}
2006-11-14 16:37:35 +03:00
block = ata_tf_read_block ( & qc - > result_tf , dev ) ;
2005-10-30 12:44:42 +03:00
2006-11-14 16:37:35 +03:00
/* information sense data descriptor */
sb [ 7 ] = 12 ;
desc [ 0 ] = 0x00 ;
desc [ 1 ] = 10 ;
2005-10-30 12:44:42 +03:00
2006-11-14 16:37:35 +03:00
desc [ 2 ] | = 0x80 ; /* valid */
desc [ 6 ] = block > > 40 ;
desc [ 7 ] = block > > 32 ;
desc [ 8 ] = block > > 24 ;
desc [ 9 ] = block > > 16 ;
desc [ 10 ] = block > > 8 ;
desc [ 11 ] = block ;
2005-04-17 02:20:36 +04:00
}
2006-03-18 02:04:15 +03:00
static void ata_scsi_sdev_config ( struct scsi_device * sdev )
{
sdev - > use_10_for_rw = 1 ;
sdev - > use_10_for_ms = 1 ;
}
static void ata_scsi_dev_config ( struct scsi_device * sdev ,
struct ata_device * dev )
{
2006-11-01 12:39:55 +03:00
/* configure max sectors */
blk_queue_max_sectors ( sdev - > request_queue , dev - > max_sectors ) ;
2006-03-18 02:04:15 +03:00
2006-11-01 12:39:55 +03:00
/* SATA DMA transfers must be multiples of 4 byte, so
2006-03-18 02:04:15 +03:00
* we need to pad ATAPI transfers using an extra sg .
* Decrement max hw segments accordingly .
*/
if ( dev - > class = = ATA_DEV_ATAPI ) {
request_queue_t * q = sdev - > request_queue ;
blk_queue_max_hw_segments ( q , q - > max_hw_segments - 1 ) ;
}
2006-05-15 16:03:48 +04:00
if ( dev - > flags & ATA_DFLAG_NCQ ) {
int depth ;
depth = min ( sdev - > host - > can_queue , ata_id_queue_depth ( dev - > id ) ) ;
depth = min ( ATA_MAX_QUEUE - 1 , depth ) ;
scsi_adjust_queue_depth ( sdev , MSG_SIMPLE_TAG , depth ) ;
}
2006-03-18 02:04:15 +03:00
}
2005-04-17 02:20:36 +04:00
/**
* ata_scsi_slave_config - Set SCSI device attributes
* @ sdev : SCSI device to examine
*
* This is called before we actually start reading
* and writing to the device , to configure certain
* SCSI mid - layer behaviors .
*
* LOCKING :
* Defined by SCSI layer . We don ' t really care .
*/
int ata_scsi_slave_config ( struct scsi_device * sdev )
{
2006-05-31 13:27:36 +04:00
struct ata_port * ap = ata_shost_to_port ( sdev - > host ) ;
struct ata_device * dev = __ata_scsi_find_dev ( ap , sdev ) ;
2006-03-18 02:04:15 +03:00
ata_scsi_sdev_config ( sdev ) ;
2005-04-17 02:20:36 +04:00
blk_queue_max_phys_segments ( sdev - > request_queue , LIBATA_MAX_PRD ) ;
2006-05-31 13:27:36 +04:00
if ( dev )
2006-03-18 02:04:15 +03:00
ata_scsi_dev_config ( sdev , dev ) ;
2005-04-17 02:20:36 +04:00
return 0 ; /* scsi layer doesn't check return value, sigh */
}
2006-05-31 13:28:07 +04:00
/**
* ata_scsi_slave_destroy - SCSI device is about to be destroyed
* @ sdev : SCSI device to be destroyed
*
* @ sdev is about to be destroyed for hot / warm unplugging . If
* this unplugging was initiated by libata as indicated by NULL
* dev - > sdev , this function doesn ' t have to do anything .
* Otherwise , SCSI layer initiated warm - unplug is in progress .
* Clear dev - > sdev , schedule the device for ATA detach and invoke
* EH .
*
* LOCKING :
* Defined by SCSI layer . We don ' t really care .
*/
void ata_scsi_slave_destroy ( struct scsi_device * sdev )
{
struct ata_port * ap = ata_shost_to_port ( sdev - > host ) ;
unsigned long flags ;
struct ata_device * dev ;
if ( ! ap - > ops - > error_handler )
return ;
2006-06-23 07:46:10 +04:00
spin_lock_irqsave ( ap - > lock , flags ) ;
2006-05-31 13:28:07 +04:00
dev = __ata_scsi_find_dev ( ap , sdev ) ;
if ( dev & & dev - > sdev ) {
/* SCSI device already in CANCEL state, no need to offline it */
dev - > sdev = NULL ;
dev - > flags | = ATA_DFLAG_DETACH ;
ata_port_schedule_eh ( ap ) ;
}
2006-06-23 07:46:10 +04:00
spin_unlock_irqrestore ( ap - > lock , flags ) ;
2006-05-31 13:28:07 +04:00
}
2006-05-15 16:03:48 +04:00
/**
* ata_scsi_change_queue_depth - SCSI callback for queue depth config
* @ sdev : SCSI device to configure queue depth for
* @ queue_depth : new queue depth
*
* This is libata standard hostt - > change_queue_depth callback .
* SCSI will call into this callback when user tries to set queue
* depth via sysfs .
*
* LOCKING :
* SCSI layer ( we don ' t care )
*
* RETURNS :
* Newly configured queue depth .
*/
int ata_scsi_change_queue_depth ( struct scsi_device * sdev , int queue_depth )
{
struct ata_port * ap = ata_shost_to_port ( sdev - > host ) ;
struct ata_device * dev ;
2006-09-30 14:45:00 +04:00
unsigned long flags ;
2006-05-15 16:03:48 +04:00
2007-02-20 17:31:22 +03:00
if ( queue_depth < 1 | | queue_depth = = sdev - > queue_depth )
2006-05-15 16:03:48 +04:00
return sdev - > queue_depth ;
dev = ata_scsi_find_dev ( ap , sdev ) ;
if ( ! dev | | ! ata_dev_enabled ( dev ) )
return sdev - > queue_depth ;
2007-02-20 17:31:22 +03:00
/* NCQ enabled? */
2006-09-30 14:45:00 +04:00
spin_lock_irqsave ( ap - > lock , flags ) ;
2007-02-20 17:31:22 +03:00
dev - > flags & = ~ ATA_DFLAG_NCQ_OFF ;
if ( queue_depth = = 1 | | ! ata_ncq_enabled ( dev ) ) {
2006-09-30 14:45:00 +04:00
dev - > flags | = ATA_DFLAG_NCQ_OFF ;
2007-02-20 17:31:22 +03:00
queue_depth = 1 ;
}
2006-09-30 14:45:00 +04:00
spin_unlock_irqrestore ( ap - > lock , flags ) ;
2007-02-20 17:31:22 +03:00
/* limit and apply queue depth */
queue_depth = min ( queue_depth , sdev - > host - > can_queue ) ;
queue_depth = min ( queue_depth , ata_id_queue_depth ( dev - > id ) ) ;
queue_depth = min ( queue_depth , ATA_MAX_QUEUE - 1 ) ;
if ( sdev - > queue_depth = = queue_depth )
return - EINVAL ;
scsi_adjust_queue_depth ( sdev , MSG_SIMPLE_TAG , queue_depth ) ;
2006-05-15 16:03:48 +04:00
return queue_depth ;
}
2005-08-11 11:35:53 +04:00
/**
* ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command
* @ qc : Storage for translated ATA taskfile
*
* Sets up an ATA taskfile to issue STANDBY ( to stop ) or READ VERIFY
* ( to start ) . Perhaps these commands should be preceded by
* CHECK POWER MODE to see what power mode the device is already in .
* [ See SAT revision 5 at www . t10 . org ]
*
* LOCKING :
2006-08-24 11:19:22 +04:00
* spin_lock_irqsave ( host lock )
2005-08-11 11:35:53 +04:00
*
* RETURNS :
* Zero on success , non - zero on error .
*/
2006-12-17 04:45:57 +03:00
static unsigned int ata_scsi_start_stop_xlat ( struct ata_queued_cmd * qc )
2005-08-11 11:35:53 +04:00
{
2006-12-17 04:45:08 +03:00
struct scsi_cmnd * scmd = qc - > scsicmd ;
2005-08-11 11:35:53 +04:00
struct ata_taskfile * tf = & qc - > tf ;
2006-12-17 04:45:57 +03:00
const u8 * cdb = scmd - > cmnd ;
2005-08-11 11:35:53 +04:00
2006-12-17 04:46:33 +03:00
if ( scmd - > cmd_len < 5 )
goto invalid_fld ;
2005-08-11 11:35:53 +04:00
tf - > flags | = ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR ;
tf - > protocol = ATA_PROT_NODATA ;
2006-12-17 04:45:08 +03:00
if ( cdb [ 1 ] & 0x1 ) {
2005-08-11 11:35:53 +04:00
; /* ignore IMMED bit, violates sat-r05 */
}
2006-12-17 04:45:08 +03:00
if ( cdb [ 4 ] & 0x2 )
2005-10-09 17:09:35 +04:00
goto invalid_fld ; /* LOEJ bit set not supported */
2006-12-17 04:45:08 +03:00
if ( ( ( cdb [ 4 ] > > 4 ) & 0xf ) ! = 0 )
2005-10-09 17:09:35 +04:00
goto invalid_fld ; /* power conditions not supported */
2006-12-17 04:45:08 +03:00
if ( cdb [ 4 ] & 0x1 ) {
2005-08-11 11:35:53 +04:00
tf - > nsect = 1 ; /* 1 sector, lba=0 */
2005-10-04 16:48:17 +04:00
if ( qc - > dev - > flags & ATA_DFLAG_LBA ) {
2006-05-15 15:57:21 +04:00
tf - > flags | = ATA_TFLAG_LBA ;
2005-10-04 16:48:17 +04:00
tf - > lbah = 0x0 ;
tf - > lbam = 0x0 ;
tf - > lbal = 0x0 ;
tf - > device | = ATA_LBA ;
} else {
/* CHS */
tf - > lbal = 0x1 ; /* sect */
tf - > lbam = 0x0 ; /* cyl low */
tf - > lbah = 0x0 ; /* cyl high */
}
2005-08-11 11:35:53 +04:00
tf - > command = ATA_CMD_VERIFY ; /* READ VERIFY */
2007-01-30 11:59:18 +03:00
} else
/* Issue ATA STANDBY IMMEDIATE command */
tf - > command = ATA_CMD_STANDBYNOW1 ;
2005-08-11 11:35:53 +04:00
/*
* Standby and Idle condition timers could be implemented but that
* would require libata to implement the Power condition mode page
* and allow the user to change it . Changing mode pages requires
* MODE SELECT to be implemented .
*/
return 0 ;
2005-10-09 17:09:35 +04:00
invalid_fld :
2006-12-17 04:45:08 +03:00
ata_scsi_set_sense ( scmd , ILLEGAL_REQUEST , 0x24 , 0x0 ) ;
2005-10-09 17:09:35 +04:00
/* "Invalid field in cbd" */
return 1 ;
2005-08-11 11:35:53 +04:00
}
2005-04-17 02:20:36 +04:00
/**
* ata_scsi_flush_xlat - Translate SCSI SYNCHRONIZE CACHE command
* @ qc : Storage for translated ATA taskfile
*
* Sets up an ATA taskfile to issue FLUSH CACHE or
* FLUSH CACHE EXT .
*
* LOCKING :
2006-08-24 11:19:22 +04:00
* spin_lock_irqsave ( host lock )
2005-04-17 02:20:36 +04:00
*
* RETURNS :
* Zero on success , non - zero on error .
*/
2006-12-17 04:45:57 +03:00
static unsigned int ata_scsi_flush_xlat ( struct ata_queued_cmd * qc )
2005-04-17 02:20:36 +04:00
{
struct ata_taskfile * tf = & qc - > tf ;
tf - > flags | = ATA_TFLAG_DEVICE ;
tf - > protocol = ATA_PROT_NODATA ;
2006-11-11 14:10:45 +03:00
if ( qc - > dev - > flags & ATA_DFLAG_FLUSH_EXT )
2005-04-17 02:20:36 +04:00
tf - > command = ATA_CMD_FLUSH_EXT ;
else
tf - > command = ATA_CMD_FLUSH ;
return 0 ;
}
2005-10-04 16:47:43 +04:00
/**
* scsi_6_lba_len - Get LBA and transfer length
2006-12-17 04:45:08 +03:00
* @ cdb : SCSI command to translate
2005-10-04 16:47:43 +04:00
*
* Calculate LBA and transfer length for 6 - byte commands .
*
* RETURNS :
* @ plba : the LBA
* @ plen : the transfer length
*/
2006-12-17 04:45:08 +03:00
static void scsi_6_lba_len ( const u8 * cdb , u64 * plba , u32 * plen )
2005-10-04 16:47:43 +04:00
{
u64 lba = 0 ;
u32 len = 0 ;
VPRINTK ( " six-byte command \n " ) ;
2006-12-17 04:45:08 +03:00
lba | = ( ( u64 ) cdb [ 2 ] ) < < 8 ;
lba | = ( ( u64 ) cdb [ 3 ] ) ;
2005-10-04 16:47:43 +04:00
2006-12-17 04:45:08 +03:00
len | = ( ( u32 ) cdb [ 4 ] ) ;
2005-10-04 16:47:43 +04:00
* plba = lba ;
* plen = len ;
}
/**
* scsi_10_lba_len - Get LBA and transfer length
2006-12-17 04:45:08 +03:00
* @ cdb : SCSI command to translate
2005-10-04 16:47:43 +04:00
*
* Calculate LBA and transfer length for 10 - byte commands .
*
* RETURNS :
* @ plba : the LBA
* @ plen : the transfer length
*/
2006-12-17 04:45:08 +03:00
static void scsi_10_lba_len ( const u8 * cdb , u64 * plba , u32 * plen )
2005-10-04 16:47:43 +04:00
{
u64 lba = 0 ;
u32 len = 0 ;
VPRINTK ( " ten-byte command \n " ) ;
2006-12-17 04:45:08 +03:00
lba | = ( ( u64 ) cdb [ 2 ] ) < < 24 ;
lba | = ( ( u64 ) cdb [ 3 ] ) < < 16 ;
lba | = ( ( u64 ) cdb [ 4 ] ) < < 8 ;
lba | = ( ( u64 ) cdb [ 5 ] ) ;
2005-10-04 16:47:43 +04:00
2006-12-17 04:45:08 +03:00
len | = ( ( u32 ) cdb [ 7 ] ) < < 8 ;
len | = ( ( u32 ) cdb [ 8 ] ) ;
2005-10-04 16:47:43 +04:00
* plba = lba ;
* plen = len ;
}
/**
* scsi_16_lba_len - Get LBA and transfer length
2006-12-17 04:45:08 +03:00
* @ cdb : SCSI command to translate
2005-10-04 16:47:43 +04:00
*
* Calculate LBA and transfer length for 16 - byte commands .
*
* RETURNS :
* @ plba : the LBA
* @ plen : the transfer length
*/
2006-12-17 04:45:08 +03:00
static void scsi_16_lba_len ( const u8 * cdb , u64 * plba , u32 * plen )
2005-10-04 16:47:43 +04:00
{
u64 lba = 0 ;
u32 len = 0 ;
VPRINTK ( " sixteen-byte command \n " ) ;
2006-12-17 04:45:08 +03:00
lba | = ( ( u64 ) cdb [ 2 ] ) < < 56 ;
lba | = ( ( u64 ) cdb [ 3 ] ) < < 48 ;
lba | = ( ( u64 ) cdb [ 4 ] ) < < 40 ;
lba | = ( ( u64 ) cdb [ 5 ] ) < < 32 ;
lba | = ( ( u64 ) cdb [ 6 ] ) < < 24 ;
lba | = ( ( u64 ) cdb [ 7 ] ) < < 16 ;
lba | = ( ( u64 ) cdb [ 8 ] ) < < 8 ;
lba | = ( ( u64 ) cdb [ 9 ] ) ;
2005-10-04 16:47:43 +04:00
2006-12-17 04:45:08 +03:00
len | = ( ( u32 ) cdb [ 10 ] ) < < 24 ;
len | = ( ( u32 ) cdb [ 11 ] ) < < 16 ;
len | = ( ( u32 ) cdb [ 12 ] ) < < 8 ;
len | = ( ( u32 ) cdb [ 13 ] ) ;
2005-10-04 16:47:43 +04:00
* plba = lba ;
* plen = len ;
}
2005-04-17 02:20:36 +04:00
/**
* ata_scsi_verify_xlat - Translate SCSI VERIFY command into an ATA one
* @ qc : Storage for translated ATA taskfile
*
* Converts SCSI VERIFY command to an ATA READ VERIFY command .
*
* LOCKING :
2006-08-24 11:19:22 +04:00
* spin_lock_irqsave ( host lock )
2005-04-17 02:20:36 +04:00
*
* RETURNS :
* Zero on success , non - zero on error .
*/
2006-12-17 04:45:57 +03:00
static unsigned int ata_scsi_verify_xlat ( struct ata_queued_cmd * qc )
2005-04-17 02:20:36 +04:00
{
2006-12-17 04:45:08 +03:00
struct scsi_cmnd * scmd = qc - > scsicmd ;
2005-04-17 02:20:36 +04:00
struct ata_taskfile * tf = & qc - > tf ;
2005-05-12 23:29:42 +04:00
struct ata_device * dev = qc - > dev ;
2005-04-17 02:20:36 +04:00
u64 dev_sectors = qc - > dev - > n_sectors ;
2006-12-17 04:45:57 +03:00
const u8 * cdb = scmd - > cmnd ;
2005-10-04 16:47:43 +04:00
u64 block ;
u32 n_block ;
2005-04-17 02:20:36 +04:00
tf - > flags | = ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE ;
tf - > protocol = ATA_PROT_NODATA ;
2006-12-17 04:46:33 +03:00
if ( cdb [ 0 ] = = VERIFY ) {
if ( scmd - > cmd_len < 10 )
goto invalid_fld ;
2006-12-17 04:45:08 +03:00
scsi_10_lba_len ( cdb , & block , & n_block ) ;
2006-12-17 04:46:33 +03:00
} else if ( cdb [ 0 ] = = VERIFY_16 ) {
if ( scmd - > cmd_len < 16 )
goto invalid_fld ;
2006-12-17 04:45:08 +03:00
scsi_16_lba_len ( cdb , & block , & n_block ) ;
2006-12-17 04:46:33 +03:00
} else
2005-10-09 17:09:35 +04:00
goto invalid_fld ;
2005-04-17 02:20:36 +04:00
2005-05-12 23:29:42 +04:00
if ( ! n_block )
2005-10-09 17:09:35 +04:00
goto nothing_to_do ;
2005-05-12 23:29:42 +04:00
if ( block > = dev_sectors )
2005-10-09 17:09:35 +04:00
goto out_of_range ;
2005-05-12 23:29:42 +04:00
if ( ( block + n_block ) > dev_sectors )
2005-10-09 17:09:35 +04:00
goto out_of_range ;
2005-04-17 02:20:36 +04:00
2005-10-12 11:04:18 +04:00
if ( dev - > flags & ATA_DFLAG_LBA ) {
tf - > flags | = ATA_TFLAG_LBA ;
2005-10-12 11:12:26 +04:00
if ( lba_28_ok ( block , n_block ) ) {
/* use LBA28 */
tf - > command = ATA_CMD_VERIFY ;
tf - > device | = ( block > > 24 ) & 0xf ;
} else if ( lba_48_ok ( block , n_block ) ) {
if ( ! ( dev - > flags & ATA_DFLAG_LBA48 ) )
goto out_of_range ;
2005-10-12 11:04:18 +04:00
/* use LBA48 */
tf - > flags | = ATA_TFLAG_LBA48 ;
2005-05-12 23:29:42 +04:00
tf - > command = ATA_CMD_VERIFY_EXT ;
2005-04-17 02:20:36 +04:00
2005-05-12 23:29:42 +04:00
tf - > hob_nsect = ( n_block > > 8 ) & 0xff ;
2005-04-17 02:20:36 +04:00
2005-05-12 23:29:42 +04:00
tf - > hob_lbah = ( block > > 40 ) & 0xff ;
tf - > hob_lbam = ( block > > 32 ) & 0xff ;
tf - > hob_lbal = ( block > > 24 ) & 0xff ;
2005-10-12 11:12:26 +04:00
} else
/* request too large even for LBA48 */
goto out_of_range ;
2005-05-12 23:29:42 +04:00
tf - > nsect = n_block & 0xff ;
2005-04-17 02:20:36 +04:00
2005-05-12 23:29:42 +04:00
tf - > lbah = ( block > > 16 ) & 0xff ;
tf - > lbam = ( block > > 8 ) & 0xff ;
tf - > lbal = block & 0xff ;
2005-04-17 02:20:36 +04:00
2005-05-12 23:29:42 +04:00
tf - > device | = ATA_LBA ;
} else {
/* CHS */
u32 sect , head , cyl , track ;
2005-10-12 11:12:26 +04:00
if ( ! lba_28_ok ( block , n_block ) )
goto out_of_range ;
2005-10-12 11:04:18 +04:00
2005-05-12 23:29:42 +04:00
/* Convert LBA to CHS */
track = ( u32 ) block / dev - > sectors ;
cyl = track / dev - > heads ;
head = track % dev - > heads ;
sect = ( u32 ) block % dev - > sectors + 1 ;
2005-10-04 16:46:51 +04:00
DPRINTK ( " block %u track %u cyl %u head %u sect %u \n " ,
( u32 ) block , track , cyl , head , sect ) ;
2006-03-24 17:56:57 +03:00
/* Check whether the converted CHS can fit.
Cylinder : 0 - 65535
2005-05-12 23:29:42 +04:00
Head : 0 - 15
Sector : 1 - 255 */
2006-03-24 17:56:57 +03:00
if ( ( cyl > > 16 ) | | ( head > > 4 ) | | ( sect > > 8 ) | | ( ! sect ) )
2005-10-09 17:09:35 +04:00
goto out_of_range ;
2006-03-24 17:56:57 +03:00
2005-05-12 23:29:42 +04:00
tf - > command = ATA_CMD_VERIFY ;
tf - > nsect = n_block & 0xff ; /* Sector count 0 means 256 sectors */
tf - > lbal = sect ;
tf - > lbam = cyl ;
tf - > lbah = cyl > > 8 ;
tf - > device | = head ;
}
2005-04-17 02:20:36 +04:00
return 0 ;
2005-10-09 17:09:35 +04:00
invalid_fld :
2006-12-17 04:45:08 +03:00
ata_scsi_set_sense ( scmd , ILLEGAL_REQUEST , 0x24 , 0x0 ) ;
2005-10-09 17:09:35 +04:00
/* "Invalid field in cbd" */
return 1 ;
out_of_range :
2006-12-17 04:45:08 +03:00
ata_scsi_set_sense ( scmd , ILLEGAL_REQUEST , 0x21 , 0x0 ) ;
2005-10-09 17:09:35 +04:00
/* "Logical Block Address out of range" */
return 1 ;
nothing_to_do :
2006-12-17 04:45:08 +03:00
scmd - > result = SAM_STAT_GOOD ;
2005-10-09 17:09:35 +04:00
return 1 ;
2005-04-17 02:20:36 +04:00
}
/**
* ata_scsi_rw_xlat - Translate SCSI r / w command into an ATA one
* @ qc : Storage for translated ATA taskfile
*
* Converts any of six SCSI read / write commands into the
* ATA counterpart , including starting sector ( LBA ) ,
* sector count , and taking into account the device ' s LBA48
* support .
*
* Commands % READ_6 , % READ_10 , % READ_16 , % WRITE_6 , % WRITE_10 , and
* % WRITE_16 are currently supported .
*
* LOCKING :
2006-08-24 11:19:22 +04:00
* spin_lock_irqsave ( host lock )
2005-04-17 02:20:36 +04:00
*
* RETURNS :
* Zero on success , non - zero on error .
*/
2006-12-17 04:45:57 +03:00
static unsigned int ata_scsi_rw_xlat ( struct ata_queued_cmd * qc )
2005-04-17 02:20:36 +04:00
{
2006-12-17 04:45:08 +03:00
struct scsi_cmnd * scmd = qc - > scsicmd ;
2006-12-17 04:45:57 +03:00
const u8 * cdb = scmd - > cmnd ;
2006-11-14 16:47:10 +03:00
unsigned int tf_flags = 0 ;
2005-10-04 16:47:43 +04:00
u64 block ;
u32 n_block ;
2006-11-14 16:47:10 +03:00
int rc ;
2005-04-17 02:20:36 +04:00
2006-12-17 04:45:08 +03:00
if ( cdb [ 0 ] = = WRITE_10 | | cdb [ 0 ] = = WRITE_6 | | cdb [ 0 ] = = WRITE_16 )
2006-11-14 16:47:10 +03:00
tf_flags | = ATA_TFLAG_WRITE ;
2005-04-17 02:20:36 +04:00
2006-01-06 11:56:18 +03:00
/* Calculate the SCSI LBA, transfer length and FUA. */
2006-12-17 04:45:08 +03:00
switch ( cdb [ 0 ] ) {
2005-10-04 16:47:43 +04:00
case READ_10 :
case WRITE_10 :
2006-12-17 04:46:33 +03:00
if ( unlikely ( scmd - > cmd_len < 10 ) )
goto invalid_fld ;
2006-12-17 04:45:08 +03:00
scsi_10_lba_len ( cdb , & block , & n_block ) ;
if ( unlikely ( cdb [ 1 ] & ( 1 < < 3 ) ) )
2006-11-14 16:47:10 +03:00
tf_flags | = ATA_TFLAG_FUA ;
2005-10-04 16:47:43 +04:00
break ;
case READ_6 :
case WRITE_6 :
2006-12-17 04:46:33 +03:00
if ( unlikely ( scmd - > cmd_len < 6 ) )
goto invalid_fld ;
2006-12-17 04:45:08 +03:00
scsi_6_lba_len ( cdb , & block , & n_block ) ;
2005-10-04 16:46:51 +04:00
/* for 6-byte r/w commands, transfer length 0
* means 256 blocks of data , not 0 block .
*/
2005-08-30 03:24:43 +04:00
if ( ! n_block )
n_block = 256 ;
2005-10-04 16:47:43 +04:00
break ;
case READ_16 :
case WRITE_16 :
2006-12-17 04:46:33 +03:00
if ( unlikely ( scmd - > cmd_len < 16 ) )
goto invalid_fld ;
2006-12-17 04:45:08 +03:00
scsi_16_lba_len ( cdb , & block , & n_block ) ;
if ( unlikely ( cdb [ 1 ] & ( 1 < < 3 ) ) )
2006-11-14 16:47:10 +03:00
tf_flags | = ATA_TFLAG_FUA ;
2005-10-04 16:47:43 +04:00
break ;
default :
2005-05-12 23:29:42 +04:00
DPRINTK ( " no-byte command \n " ) ;
2005-10-09 17:09:35 +04:00
goto invalid_fld ;
2005-04-17 02:20:36 +04:00
}
2005-05-12 23:29:42 +04:00
/* Check and compose ATA command */
if ( ! n_block )
2005-10-04 16:46:51 +04:00
/* For 10-byte and 16-byte SCSI R/W commands, transfer
* length 0 means transfer 0 block of data .
* However , for ATA R / W commands , sector count 0 means
* 256 or 65536 sectors , not 0 sectors as in SCSI .
2005-11-07 20:06:33 +03:00
*
* WARNING : one or two older ATA drives treat 0 as 0. . .
2005-10-04 16:46:51 +04:00
*/
2005-10-09 17:09:35 +04:00
goto nothing_to_do ;
2005-04-17 02:20:36 +04:00
2006-11-14 16:47:10 +03:00
qc - > flags | = ATA_QCFLAG_IO ;
2007-01-03 11:30:39 +03:00
qc - > nbytes = n_block * ATA_SECT_SIZE ;
2005-04-17 02:20:36 +04:00
2006-11-14 16:47:10 +03:00
rc = ata_build_rw_tf ( & qc - > tf , qc - > dev , block , n_block , tf_flags ,
qc - > tag ) ;
if ( likely ( rc = = 0 ) )
return 0 ;
2005-10-09 17:09:35 +04:00
2006-11-14 16:47:10 +03:00
if ( rc = = - ERANGE )
goto out_of_range ;
/* treat all other errors as -EINVAL, fall through */
2005-10-09 17:09:35 +04:00
invalid_fld :
2006-12-17 04:45:08 +03:00
ata_scsi_set_sense ( scmd , ILLEGAL_REQUEST , 0x24 , 0x0 ) ;
2005-10-09 17:09:35 +04:00
/* "Invalid field in cbd" */
return 1 ;
out_of_range :
2006-12-17 04:45:08 +03:00
ata_scsi_set_sense ( scmd , ILLEGAL_REQUEST , 0x21 , 0x0 ) ;
2005-10-09 17:09:35 +04:00
/* "Logical Block Address out of range" */
return 1 ;
nothing_to_do :
2006-12-17 04:45:08 +03:00
scmd - > result = SAM_STAT_GOOD ;
2005-10-09 17:09:35 +04:00
return 1 ;
2005-04-17 02:20:36 +04:00
}
2006-01-23 07:09:36 +03:00
static void ata_scsi_qc_complete ( struct ata_queued_cmd * qc )
2005-04-17 02:20:36 +04:00
{
2006-11-22 06:39:43 +03:00
struct ata_port * ap = qc - > ap ;
2005-04-17 02:20:36 +04:00
struct scsi_cmnd * cmd = qc - > scsicmd ;
2005-10-30 12:44:42 +03:00
u8 * cdb = cmd - > cmnd ;
2005-12-05 10:38:02 +03:00
int need_sense = ( qc - > err_mask ! = 0 ) ;
2005-05-12 23:45:22 +04:00
2006-06-12 08:01:34 +04:00
/* We snoop the SET_FEATURES - Write Cache ON/OFF command, and
* schedule EH_REVALIDATE operation to update the IDENTIFY DEVICE
* cache
*/
2006-11-22 06:39:43 +03:00
if ( ap - > ops - > error_handler & &
! need_sense & & ( qc - > tf . command = = ATA_CMD_SET_FEATURES ) & &
2006-06-12 08:01:34 +04:00
( ( qc - > tf . feature = = SETFEATURES_WC_ON ) | |
( qc - > tf . feature = = SETFEATURES_WC_OFF ) ) ) {
2006-11-22 06:39:43 +03:00
ap - > eh_info . action | = ATA_EH_REVALIDATE ;
ata_port_schedule_eh ( ap ) ;
2006-06-12 08:01:34 +04:00
}
2005-05-12 23:45:22 +04:00
/* For ATA pass thru (SAT) commands, generate a sense block if
* user mandated it or if there ' s an error . Note that if we
* generate because the user forced us to , a check condition
* is generated and the ATA register values are returned
* whether the command completed successfully or not . If there
* was no error , SK , ASC and ASCQ will all be zero .
*/
2005-10-30 12:44:42 +03:00
if ( ( ( cdb [ 0 ] = = ATA_16 ) | | ( cdb [ 0 ] = = ATA_12 ) ) & &
( ( cdb [ 2 ] & 0x20 ) | | need_sense ) ) {
2006-11-14 16:37:35 +03:00
ata_gen_passthru_sense ( qc ) ;
2005-05-12 23:45:22 +04:00
} else {
if ( ! need_sense ) {
cmd - > result = SAM_STAT_GOOD ;
} else {
/* TODO: decide which descriptor format to use
* for 48 b LBA devices and call that here
* instead of the fixed desc , which is only
* good for smaller LBA ( and maybe CHS ? )
* devices .
*/
2006-11-14 16:37:35 +03:00
ata_gen_ata_sense ( qc ) ;
2005-05-12 23:45:22 +04:00
}
}
2005-04-17 02:20:36 +04:00
2006-11-22 06:39:43 +03:00
if ( need_sense & & ! ap - > ops - > error_handler )
2007-02-20 19:06:51 +03:00
ata_dump_status ( ap - > print_id , & qc - > result_tf ) ;
2005-04-17 02:20:36 +04:00
qc - > scsidone ( cmd ) ;
2006-01-23 07:09:36 +03:00
ata_qc_free ( qc ) ;
2005-04-17 02:20:36 +04:00
}
2006-05-15 16:03:45 +04:00
/**
* ata_scmd_need_defer - Check whether we need to defer scmd
* @ dev : ATA device to which the command is addressed
* @ is_io : Is the command IO ( and thus possibly NCQ ) ?
*
* NCQ and non - NCQ commands cannot run together . As upper layer
* only knows the queue depth , we are responsible for maintaining
* exclusion . This function checks whether a new command can be
* issued to @ dev .
*
* LOCKING :
2006-08-24 11:19:22 +04:00
* spin_lock_irqsave ( host lock )
2006-05-15 16:03:45 +04:00
*
* RETURNS :
* 1 if deferring is needed , 0 otherwise .
*/
static int ata_scmd_need_defer ( struct ata_device * dev , int is_io )
{
struct ata_port * ap = dev - > ap ;
2007-02-20 17:27:06 +03:00
int is_ncq = is_io & & ata_ncq_enabled ( dev ) ;
2006-05-15 16:03:45 +04:00
2007-02-20 17:27:06 +03:00
if ( is_ncq ) {
2006-05-15 16:03:45 +04:00
if ( ! ata_tag_valid ( ap - > active_tag ) )
return 0 ;
} else {
if ( ! ata_tag_valid ( ap - > active_tag ) & & ! ap - > sactive )
return 0 ;
}
return 1 ;
}
2005-04-17 02:20:36 +04:00
/**
* ata_scsi_translate - Translate then issue SCSI command to ATA device
* @ dev : ATA device to which the command is addressed
* @ cmd : SCSI command to execute
* @ done : SCSI command completion function
* @ xlat_func : Actor which translates @ cmd to an ATA taskfile
*
* Our - > queuecommand ( ) function has decided that the SCSI
* command issued can be directly translated into an ATA
* command , rather than handled internally .
*
* This function sets up an ata_queued_cmd structure for the
* SCSI command , and sends that ata_queued_cmd to the hardware .
*
2005-10-09 17:09:35 +04:00
* The xlat_func argument ( actor ) returns 0 if ready to execute
* ATA command , else 1 to finish translation . If 1 is returned
* then cmd - > result ( and possibly cmd - > sense_buffer ) are assumed
* to be set reflecting an error condition or clean ( early )
* termination .
*
2005-04-17 02:20:36 +04:00
* LOCKING :
2006-08-24 11:19:22 +04:00
* spin_lock_irqsave ( host lock )
2006-05-15 16:03:39 +04:00
*
* RETURNS :
* 0 on success , SCSI_ML_QUEUE_DEVICE_BUSY if the command
* needs to be deferred .
2005-04-17 02:20:36 +04:00
*/
2006-05-15 16:03:39 +04:00
static int ata_scsi_translate ( struct ata_device * dev , struct scsi_cmnd * cmd ,
void ( * done ) ( struct scsi_cmnd * ) ,
ata_xlat_func_t xlat_func )
2005-04-17 02:20:36 +04:00
{
struct ata_queued_cmd * qc ;
2006-05-15 16:03:45 +04:00
int is_io = xlat_func = = ata_scsi_rw_xlat ;
2005-04-17 02:20:36 +04:00
VPRINTK ( " ENTER \n " ) ;
2006-05-15 16:03:45 +04:00
if ( unlikely ( ata_scmd_need_defer ( dev , is_io ) ) )
goto defer ;
2006-05-15 15:57:53 +04:00
qc = ata_scsi_qc_new ( dev , cmd , done ) ;
2005-04-17 02:20:36 +04:00
if ( ! qc )
2005-10-09 17:09:35 +04:00
goto err_mem ;
2005-04-17 02:20:36 +04:00
/* data is present; dma-map it */
2005-04-18 00:26:13 +04:00
if ( cmd - > sc_data_direction = = DMA_FROM_DEVICE | |
cmd - > sc_data_direction = = DMA_TO_DEVICE ) {
2005-04-17 02:20:36 +04:00
if ( unlikely ( cmd - > request_bufflen < 1 ) ) {
2006-05-15 15:57:56 +04:00
ata_dev_printk ( dev , KERN_WARNING ,
" WARNING: zero len r/w req \n " ) ;
2005-10-09 17:09:35 +04:00
goto err_did ;
2005-04-17 02:20:36 +04:00
}
if ( cmd - > use_sg )
ata_sg_init ( qc , cmd - > request_buffer , cmd - > use_sg ) ;
else
ata_sg_init_one ( qc , cmd - > request_buffer ,
cmd - > request_bufflen ) ;
qc - > dma_dir = cmd - > sc_data_direction ;
}
qc - > complete_fn = ata_scsi_qc_complete ;
2006-12-17 04:45:57 +03:00
if ( xlat_func ( qc ) )
2005-10-09 17:09:35 +04:00
goto early_finish ;
2005-04-17 02:20:36 +04:00
/* select device, send command to hardware */
2006-03-31 15:41:11 +04:00
ata_qc_issue ( qc ) ;
2005-04-17 02:20:36 +04:00
VPRINTK ( " EXIT \n " ) ;
2006-05-15 16:03:39 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
2005-10-09 17:09:35 +04:00
early_finish :
ata_qc_free ( qc ) ;
done ( cmd ) ;
DPRINTK ( " EXIT - early finish (good or error) \n " ) ;
2006-05-15 16:03:39 +04:00
return 0 ;
2005-10-09 17:09:35 +04:00
err_did :
2005-04-17 02:20:36 +04:00
ata_qc_free ( qc ) ;
2005-10-09 17:09:35 +04:00
cmd - > result = ( DID_ERROR < < 16 ) ;
done ( cmd ) ;
2006-11-14 17:55:41 +03:00
err_mem :
2005-10-09 17:09:35 +04:00
DPRINTK ( " EXIT - internal \n " ) ;
2006-05-15 16:03:39 +04:00
return 0 ;
2006-05-15 16:03:45 +04:00
defer :
DPRINTK ( " EXIT - defer \n " ) ;
return SCSI_MLQUEUE_DEVICE_BUSY ;
2005-04-17 02:20:36 +04:00
}
/**
* ata_scsi_rbuf_get - Map response buffer .
* @ cmd : SCSI command containing buffer to be mapped .
* @ buf_out : Pointer to mapped area .
*
* Maps buffer contained within SCSI command @ cmd .
*
* LOCKING :
2006-08-24 11:19:22 +04:00
* spin_lock_irqsave ( host lock )
2005-04-17 02:20:36 +04:00
*
* RETURNS :
* Length of response buffer .
*/
static unsigned int ata_scsi_rbuf_get ( struct scsi_cmnd * cmd , u8 * * buf_out )
{
u8 * buf ;
unsigned int buflen ;
if ( cmd - > use_sg ) {
struct scatterlist * sg ;
sg = ( struct scatterlist * ) cmd - > request_buffer ;
2006-12-11 19:05:53 +03:00
buf = kmap_atomic ( sg - > page , KM_IRQ0 ) + sg - > offset ;
2005-04-17 02:20:36 +04:00
buflen = sg - > length ;
} else {
buf = cmd - > request_buffer ;
buflen = cmd - > request_bufflen ;
}
* buf_out = buf ;
return buflen ;
}
/**
* ata_scsi_rbuf_put - Unmap response buffer .
* @ cmd : SCSI command containing buffer to be unmapped .
* @ buf : buffer to unmap
*
* Unmaps response buffer contained within @ cmd .
*
* LOCKING :
2006-08-24 11:19:22 +04:00
* spin_lock_irqsave ( host lock )
2005-04-17 02:20:36 +04:00
*/
static inline void ata_scsi_rbuf_put ( struct scsi_cmnd * cmd , u8 * buf )
{
if ( cmd - > use_sg ) {
struct scatterlist * sg ;
sg = ( struct scatterlist * ) cmd - > request_buffer ;
2006-12-11 19:05:53 +03:00
kunmap_atomic ( buf - sg - > offset , KM_IRQ0 ) ;
2005-04-17 02:20:36 +04:00
}
}
/**
* ata_scsi_rbuf_fill - wrapper for SCSI command simulators
* @ args : device IDENTIFY data / SCSI command of interest .
* @ actor : Callback hook for desired SCSI command simulator
*
* Takes care of the hard work of simulating a SCSI command . . .
* Mapping the response buffer , calling the command ' s handler ,
* and handling the handler ' s return value . This return value
* indicates whether the handler wishes the SCSI command to be
2005-10-09 17:09:35 +04:00
* completed successfully ( 0 ) , or not ( in which case cmd - > result
* and sense buffer are assumed to be set ) .
2005-04-17 02:20:36 +04:00
*
* LOCKING :
2006-08-24 11:19:22 +04:00
* spin_lock_irqsave ( host lock )
2005-04-17 02:20:36 +04:00
*/
void ata_scsi_rbuf_fill ( struct ata_scsi_args * args ,
unsigned int ( * actor ) ( struct ata_scsi_args * args ,
u8 * rbuf , unsigned int buflen ) )
{
u8 * rbuf ;
unsigned int buflen , rc ;
struct scsi_cmnd * cmd = args - > cmd ;
buflen = ata_scsi_rbuf_get ( cmd , & rbuf ) ;
memset ( rbuf , 0 , buflen ) ;
rc = actor ( args , rbuf , buflen ) ;
ata_scsi_rbuf_put ( cmd , rbuf ) ;
2005-10-09 17:09:35 +04:00
if ( rc = = 0 )
2005-04-17 02:20:36 +04:00
cmd - > result = SAM_STAT_GOOD ;
2005-10-09 17:09:35 +04:00
args - > done ( cmd ) ;
2005-04-17 02:20:36 +04:00
}
2006-11-20 05:15:47 +03:00
/**
* 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 )
2005-04-17 02:20:36 +04:00
/**
* ata_scsiop_inq_std - Simulate INQUIRY command
* @ args : device IDENTIFY data / SCSI command of interest .
* @ rbuf : Response buffer , to which simulated SCSI cmd output is sent .
* @ buflen : Response buffer length .
*
* Returns standard device identification data associated
2006-03-22 04:37:47 +03:00
* with non - VPD INQUIRY command output .
2005-04-17 02:20:36 +04:00
*
* LOCKING :
2006-08-24 11:19:22 +04:00
* spin_lock_irqsave ( host lock )
2005-04-17 02:20:36 +04:00
*/
unsigned int ata_scsiop_inq_std ( struct ata_scsi_args * args , u8 * rbuf ,
unsigned int buflen )
{
u8 hdr [ ] = {
TYPE_DISK ,
0 ,
0x5 , /* claim SPC-3 version compatibility */
2 ,
95 - 4
} ;
/* set scsi removeable (RMB) bit per ata bit */
if ( ata_id_removeable ( args - > id ) )
hdr [ 1 ] | = ( 1 < < 7 ) ;
VPRINTK ( " ENTER \n " ) ;
memcpy ( rbuf , hdr , sizeof ( hdr ) ) ;
if ( buflen > 35 ) {
memcpy ( & rbuf [ 8 ] , " ATA " , 8 ) ;
2007-01-02 14:18:49 +03:00
ata_id_string ( args - > id , & rbuf [ 16 ] , ATA_ID_PROD , 16 ) ;
ata_id_string ( args - > id , & rbuf [ 32 ] , ATA_ID_FW_REV , 4 ) ;
2005-04-17 02:20:36 +04:00
if ( rbuf [ 32 ] = = 0 | | rbuf [ 32 ] = = ' ' )
memcpy ( & rbuf [ 32 ] , " n/a " , 4 ) ;
}
if ( buflen > 63 ) {
const u8 versions [ ] = {
0x60 , /* SAM-3 (no version claimed) */
0x03 ,
0x20 , /* SBC-2 (no version claimed) */
0x02 ,
0x60 /* SPC-3 (no version claimed) */
} ;
memcpy ( rbuf + 59 , versions , sizeof ( versions ) ) ;
}
return 0 ;
}
/**
2006-03-22 04:37:47 +03:00
* ata_scsiop_inq_00 - Simulate INQUIRY VPD page 0 , list of pages
2005-04-17 02:20:36 +04:00
* @ args : device IDENTIFY data / SCSI command of interest .
* @ rbuf : Response buffer , to which simulated SCSI cmd output is sent .
* @ buflen : Response buffer length .
*
2006-03-22 04:37:47 +03:00
* Returns list of inquiry VPD pages available .
2005-04-17 02:20:36 +04:00
*
* LOCKING :
2006-08-24 11:19:22 +04:00
* spin_lock_irqsave ( host lock )
2005-04-17 02:20:36 +04:00
*/
unsigned int ata_scsiop_inq_00 ( struct ata_scsi_args * args , u8 * rbuf ,
unsigned int buflen )
{
const u8 pages [ ] = {
0x00 , /* page 0x00, this page */
0x80 , /* page 0x80, unit serial no page */
0x83 /* page 0x83, device ident page */
} ;
2006-03-22 04:37:47 +03:00
rbuf [ 3 ] = sizeof ( pages ) ; /* number of supported VPD pages */
2005-04-17 02:20:36 +04:00
if ( buflen > 6 )
memcpy ( rbuf + 4 , pages , sizeof ( pages ) ) ;
return 0 ;
}
/**
2006-03-22 04:37:47 +03:00
* ata_scsiop_inq_80 - Simulate INQUIRY VPD page 80 , device serial number
2005-04-17 02:20:36 +04:00
* @ args : device IDENTIFY data / SCSI command of interest .
* @ rbuf : Response buffer , to which simulated SCSI cmd output is sent .
* @ buflen : Response buffer length .
*
* Returns ATA device serial number .
*
* LOCKING :
2006-08-24 11:19:22 +04:00
* spin_lock_irqsave ( host lock )
2005-04-17 02:20:36 +04:00
*/
unsigned int ata_scsiop_inq_80 ( struct ata_scsi_args * args , u8 * rbuf ,
unsigned int buflen )
{
const u8 hdr [ ] = {
0 ,
0x80 , /* this page code */
0 ,
2007-01-02 14:18:49 +03:00
ATA_ID_SERNO_LEN , /* page len */
2005-04-17 02:20:36 +04:00
} ;
memcpy ( rbuf , hdr , sizeof ( hdr ) ) ;
2007-01-02 14:18:49 +03:00
if ( buflen > ( ATA_ID_SERNO_LEN + 4 - 1 ) )
2006-02-13 04:02:46 +03:00
ata_id_string ( args - > id , ( unsigned char * ) & rbuf [ 4 ] ,
2007-01-02 14:18:49 +03:00
ATA_ID_SERNO , ATA_ID_SERNO_LEN ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/**
2006-03-22 04:37:47 +03:00
* ata_scsiop_inq_83 - Simulate INQUIRY VPD page 83 , device identity
2005-04-17 02:20:36 +04:00
* @ args : device IDENTIFY data / SCSI command of interest .
* @ rbuf : Response buffer , to which simulated SCSI cmd output is sent .
* @ buflen : Response buffer length .
*
2006-03-22 04:37:47 +03:00
* Yields two logical unit device identification designators :
* - vendor specific ASCII containing the ATA serial number
* - SAT defined " t10 vendor id based " containing ASCII vendor
* name ( " ATA " ) , model and serial numbers .
2005-04-17 02:20:36 +04:00
*
* LOCKING :
2006-08-24 11:19:22 +04:00
* spin_lock_irqsave ( host lock )
2005-04-17 02:20:36 +04:00
*/
unsigned int ata_scsiop_inq_83 ( struct ata_scsi_args * args , u8 * rbuf ,
unsigned int buflen )
{
2006-03-22 04:37:47 +03:00
int num ;
const int sat_model_serial_desc_len = 68 ;
2005-04-17 02:20:36 +04:00
2006-03-22 04:37:47 +03:00
rbuf [ 1 ] = 0x83 ; /* this page code */
num = 4 ;
2007-01-02 14:18:49 +03:00
if ( buflen > ( ATA_ID_SERNO_LEN + num + 3 ) ) {
2006-03-22 04:37:47 +03:00
/* piv=0, assoc=lu, code_set=ACSII, designator=vendor */
2006-03-24 17:56:57 +03:00
rbuf [ num + 0 ] = 2 ;
2007-01-02 14:18:49 +03:00
rbuf [ num + 3 ] = ATA_ID_SERNO_LEN ;
2006-03-22 04:37:47 +03:00
num + = 4 ;
ata_id_string ( args - > id , ( unsigned char * ) rbuf + num ,
2007-01-02 14:18:49 +03:00
ATA_ID_SERNO , ATA_ID_SERNO_LEN ) ;
num + = ATA_ID_SERNO_LEN ;
2005-04-17 02:20:36 +04:00
}
2006-03-22 04:37:47 +03:00
if ( buflen > ( sat_model_serial_desc_len + num + 3 ) ) {
/* SAT defined lu model and serial numbers descriptor */
/* piv=0, assoc=lu, code_set=ACSII, designator=t10 vendor id */
2006-03-24 17:56:57 +03:00
rbuf [ num + 0 ] = 2 ;
rbuf [ num + 1 ] = 1 ;
2006-03-22 04:37:47 +03:00
rbuf [ num + 3 ] = sat_model_serial_desc_len ;
num + = 4 ;
memcpy ( rbuf + num , " ATA " , 8 ) ;
num + = 8 ;
ata_id_string ( args - > id , ( unsigned char * ) rbuf + num ,
2007-01-02 14:18:49 +03:00
ATA_ID_PROD , ATA_ID_PROD_LEN ) ;
num + = ATA_ID_PROD_LEN ;
2006-03-22 04:37:47 +03:00
ata_id_string ( args - > id , ( unsigned char * ) rbuf + num ,
2007-01-02 14:18:49 +03:00
ATA_ID_SERNO , ATA_ID_SERNO_LEN ) ;
num + = ATA_ID_SERNO_LEN ;
2006-03-22 04:37:47 +03:00
}
rbuf [ 3 ] = num - 4 ; /* page len (assume less than 256 bytes) */
2005-04-17 02:20:36 +04:00
return 0 ;
}
/**
2005-05-31 03:49:12 +04:00
* ata_scsiop_noop - Command handler that simply returns success .
2005-04-17 02:20:36 +04:00
* @ args : device IDENTIFY data / SCSI command of interest .
* @ rbuf : Response buffer , to which simulated SCSI cmd output is sent .
* @ buflen : Response buffer length .
*
* No operation . Simply returns success to caller , to indicate
* that the caller should successfully complete this SCSI command .
*
* LOCKING :
2006-08-24 11:19:22 +04:00
* spin_lock_irqsave ( host lock )
2005-04-17 02:20:36 +04:00
*/
unsigned int ata_scsiop_noop ( struct ata_scsi_args * args , u8 * rbuf ,
unsigned int buflen )
{
VPRINTK ( " ENTER \n " ) ;
return 0 ;
}
/**
* ata_msense_push - Push data onto MODE SENSE data output buffer
* @ ptr_io : ( input / output ) Location to store more output data
* @ last : End of output data buffer
* @ buf : Pointer to BLOB being added to output buffer
* @ buflen : Length of BLOB
*
* Store MODE SENSE data on an output buffer .
*
* LOCKING :
* None .
*/
static void ata_msense_push ( u8 * * ptr_io , const u8 * last ,
const u8 * buf , unsigned int buflen )
{
u8 * ptr = * ptr_io ;
if ( ( ptr + buflen - 1 ) > last )
return ;
memcpy ( ptr , buf , buflen ) ;
ptr + = buflen ;
* ptr_io = ptr ;
}
/**
* ata_msense_caching - Simulate MODE SENSE caching info page
* @ id : device IDENTIFY data
* @ ptr_io : ( input / output ) Location to store more output data
* @ last : End of output data buffer
*
* Generate a caching info page , which conditionally indicates
* write caching to the SCSI layer , depending on device
* capabilities .
*
* LOCKING :
* None .
*/
static unsigned int ata_msense_caching ( u16 * id , u8 * * ptr_io ,
const u8 * last )
{
2005-10-28 23:58:28 +04:00
u8 page [ CACHE_MPAGE_LEN ] ;
2005-04-17 02:20:36 +04:00
2005-10-28 23:58:28 +04:00
memcpy ( page , def_cache_mpage , sizeof ( page ) ) ;
2005-04-17 02:20:36 +04:00
if ( ata_id_wcache_enabled ( id ) )
page [ 2 ] | = ( 1 < < 2 ) ; /* write cache enable */
if ( ! ata_id_rahead_enabled ( id ) )
page [ 12 ] | = ( 1 < < 5 ) ; /* disable read ahead */
ata_msense_push ( ptr_io , last , page , sizeof ( page ) ) ;
return sizeof ( page ) ;
}
/**
* ata_msense_ctl_mode - Simulate MODE SENSE control mode page
* @ dev : Device associated with this MODE SENSE command
* @ ptr_io : ( input / output ) Location to store more output data
* @ last : End of output data buffer
*
* Generate a generic MODE SENSE control mode page .
*
* LOCKING :
* None .
*/
static unsigned int ata_msense_ctl_mode ( u8 * * ptr_io , const u8 * last )
{
2005-10-28 23:58:28 +04:00
ata_msense_push ( ptr_io , last , def_control_mpage ,
sizeof ( def_control_mpage ) ) ;
return sizeof ( def_control_mpage ) ;
2005-04-17 02:20:36 +04:00
}
/**
* ata_msense_rw_recovery - Simulate MODE SENSE r / w error recovery page
* @ dev : Device associated with this MODE SENSE command
* @ ptr_io : ( input / output ) Location to store more output data
* @ last : End of output data buffer
*
* Generate a generic MODE SENSE r / w error recovery page .
*
* LOCKING :
* None .
*/
static unsigned int ata_msense_rw_recovery ( u8 * * ptr_io , const u8 * last )
{
2005-10-28 23:58:28 +04:00
ata_msense_push ( ptr_io , last , def_rw_recovery_mpage ,
sizeof ( def_rw_recovery_mpage ) ) ;
return sizeof ( def_rw_recovery_mpage ) ;
2005-04-17 02:20:36 +04:00
}
2006-01-30 18:09:35 +03:00
/*
* We can turn this into a real blacklist if it ' s needed , for now just
* blacklist any Maxtor BANC1G10 revision firmware
*/
static int ata_dev_supports_fua ( u16 * id )
{
2007-01-02 14:18:49 +03:00
unsigned char model [ ATA_ID_PROD_LEN + 1 ] , fw [ ATA_ID_FW_REV_LEN + 1 ] ;
2006-01-30 18:09:35 +03:00
2006-02-28 06:31:19 +03:00
if ( ! libata_fua )
return 0 ;
2006-01-30 18:09:35 +03:00
if ( ! ata_id_has_fua ( id ) )
return 0 ;
2007-01-02 14:18:49 +03:00
ata_id_c_string ( id , model , ATA_ID_PROD , sizeof ( model ) ) ;
ata_id_c_string ( id , fw , ATA_ID_FW_REV , sizeof ( fw ) ) ;
2006-01-30 18:09:35 +03:00
2006-02-12 16:47:04 +03:00
if ( strcmp ( model , " Maxtor " ) )
2006-01-30 18:09:35 +03:00
return 1 ;
2006-02-12 16:47:04 +03:00
if ( strcmp ( fw , " BANC1G10 " ) )
2006-01-30 18:09:35 +03:00
return 1 ;
return 0 ; /* blacklisted */
}
2005-04-17 02:20:36 +04:00
/**
* ata_scsiop_mode_sense - Simulate MODE SENSE 6 , 10 commands
* @ args : device IDENTIFY data / SCSI command of interest .
* @ rbuf : Response buffer , to which simulated SCSI cmd output is sent .
* @ buflen : Response buffer length .
*
2005-10-28 23:58:28 +04:00
* Simulate MODE SENSE commands . Assume this is invoked for direct
* access devices ( e . g . disks ) only . There should be no block
* descriptor for other device types .
2005-04-17 02:20:36 +04:00
*
* LOCKING :
2006-08-24 11:19:22 +04:00
* spin_lock_irqsave ( host lock )
2005-04-17 02:20:36 +04:00
*/
unsigned int ata_scsiop_mode_sense ( struct ata_scsi_args * args , u8 * rbuf ,
unsigned int buflen )
{
2006-01-06 11:56:18 +03:00
struct ata_device * dev = args - > dev ;
2005-04-17 02:20:36 +04:00
u8 * scsicmd = args - > cmd - > cmnd , * p , * last ;
2005-10-28 23:58:28 +04:00
const u8 sat_blk_desc [ ] = {
0 , 0 , 0 , 0 , /* number of blocks: sat unspecified */
0 ,
0 , 0x2 , 0x0 /* block length: 512 bytes */
} ;
u8 pg , spg ;
unsigned int ebd , page_control , six_byte , output_len , alloc_len , minlen ;
2006-01-06 11:56:18 +03:00
u8 dpofua ;
2005-04-17 02:20:36 +04:00
VPRINTK ( " ENTER \n " ) ;
six_byte = ( scsicmd [ 0 ] = = MODE_SENSE ) ;
2005-10-28 23:58:28 +04:00
ebd = ! ( scsicmd [ 1 ] & 0x8 ) ; /* dbd bit inverted == edb */
/*
* LLBA bit in msense ( 10 ) ignored ( compliant )
2005-04-17 02:20:36 +04:00
*/
2005-10-28 23:58:28 +04:00
2005-04-17 02:20:36 +04:00
page_control = scsicmd [ 2 ] > > 6 ;
2005-10-09 17:09:35 +04:00
switch ( page_control ) {
case 0 : /* current */
break ; /* supported */
case 3 : /* saved */
goto saving_not_supp ;
case 1 : /* changeable */
case 2 : /* defaults */
default :
goto invalid_fld ;
}
2005-04-17 02:20:36 +04:00
2005-10-28 23:58:28 +04:00
if ( six_byte ) {
output_len = 4 + ( ebd ? 8 : 0 ) ;
alloc_len = scsicmd [ 4 ] ;
} else {
output_len = 8 + ( ebd ? 8 : 0 ) ;
alloc_len = ( scsicmd [ 7 ] < < 8 ) + scsicmd [ 8 ] ;
}
minlen = ( alloc_len < buflen ) ? alloc_len : buflen ;
2005-04-17 02:20:36 +04:00
p = rbuf + output_len ;
2005-10-28 23:58:28 +04:00
last = rbuf + minlen - 1 ;
2005-04-17 02:20:36 +04:00
2005-10-28 23:58:28 +04:00
pg = scsicmd [ 2 ] & 0x3f ;
spg = scsicmd [ 3 ] ;
/*
* No mode subpages supported ( yet ) but asking for _all_
* subpages may be valid
*/
if ( spg & & ( spg ! = ALL_SUB_MPAGES ) )
goto invalid_fld ;
switch ( pg ) {
case RW_RECOVERY_MPAGE :
2005-04-17 02:20:36 +04:00
output_len + = ata_msense_rw_recovery ( & p , last ) ;
break ;
2005-10-28 23:58:28 +04:00
case CACHE_MPAGE :
2005-04-17 02:20:36 +04:00
output_len + = ata_msense_caching ( args - > id , & p , last ) ;
break ;
2005-10-28 23:58:28 +04:00
case CONTROL_MPAGE : {
2005-04-17 02:20:36 +04:00
output_len + = ata_msense_ctl_mode ( & p , last ) ;
break ;
}
2005-10-28 23:58:28 +04:00
case ALL_MPAGES :
2005-04-17 02:20:36 +04:00
output_len + = ata_msense_rw_recovery ( & p , last ) ;
output_len + = ata_msense_caching ( args - > id , & p , last ) ;
output_len + = ata_msense_ctl_mode ( & p , last ) ;
break ;
default : /* invalid page code */
2005-10-09 17:09:35 +04:00
goto invalid_fld ;
2005-04-17 02:20:36 +04:00
}
2005-10-28 23:58:28 +04:00
if ( minlen < 1 )
return 0 ;
2006-01-06 11:56:18 +03:00
dpofua = 0 ;
2006-05-22 19:55:11 +04:00
if ( ata_dev_supports_fua ( args - > id ) & & ( dev - > flags & ATA_DFLAG_LBA48 ) & &
2006-01-06 11:56:18 +03:00
( ! ( dev - > flags & ATA_DFLAG_PIO ) | | dev - > multi_count ) )
dpofua = 1 < < 4 ;
2005-04-17 02:20:36 +04:00
if ( six_byte ) {
output_len - - ;
rbuf [ 0 ] = output_len ;
2006-01-06 11:56:18 +03:00
if ( minlen > 2 )
rbuf [ 2 ] | = dpofua ;
2005-10-28 23:58:28 +04:00
if ( ebd ) {
if ( minlen > 3 )
rbuf [ 3 ] = sizeof ( sat_blk_desc ) ;
if ( minlen > 11 )
memcpy ( rbuf + 4 , sat_blk_desc ,
sizeof ( sat_blk_desc ) ) ;
}
2005-04-17 02:20:36 +04:00
} else {
output_len - = 2 ;
rbuf [ 0 ] = output_len > > 8 ;
2005-10-28 23:58:28 +04:00
if ( minlen > 1 )
rbuf [ 1 ] = output_len ;
2006-01-06 11:56:18 +03:00
if ( minlen > 3 )
rbuf [ 3 ] | = dpofua ;
2005-10-28 23:58:28 +04:00
if ( ebd ) {
if ( minlen > 7 )
rbuf [ 7 ] = sizeof ( sat_blk_desc ) ;
if ( minlen > 15 )
memcpy ( rbuf + 8 , sat_blk_desc ,
sizeof ( sat_blk_desc ) ) ;
}
2005-04-17 02:20:36 +04:00
}
return 0 ;
2005-10-09 17:09:35 +04:00
invalid_fld :
ata_scsi_set_sense ( args - > cmd , ILLEGAL_REQUEST , 0x24 , 0x0 ) ;
/* "Invalid field in cbd" */
return 1 ;
saving_not_supp :
ata_scsi_set_sense ( args - > cmd , ILLEGAL_REQUEST , 0x39 , 0x0 ) ;
/* "Saving parameters not supported" */
return 1 ;
2005-04-17 02:20:36 +04:00
}
/**
* ata_scsiop_read_cap - Simulate READ CAPACITY [ 16 ] commands
* @ args : device IDENTIFY data / SCSI command of interest .
* @ rbuf : Response buffer , to which simulated SCSI cmd output is sent .
* @ buflen : Response buffer length .
*
* Simulate READ CAPACITY commands .
*
* LOCKING :
2006-11-20 05:15:47 +03:00
* None .
2005-04-17 02:20:36 +04:00
*/
unsigned int ata_scsiop_read_cap ( struct ata_scsi_args * args , u8 * rbuf ,
unsigned int buflen )
{
2006-11-20 05:15:47 +03:00
u64 last_lba = args - > dev - > n_sectors - 1 ; /* LBA of the last block */
2005-04-17 02:20:36 +04:00
VPRINTK ( " ENTER \n " ) ;
if ( args - > cmd - > cmnd [ 0 ] = = READ_CAPACITY ) {
2006-11-20 05:15:47 +03:00
if ( last_lba > = 0xffffffffULL )
last_lba = 0xffffffff ;
2005-05-28 12:24:47 +04:00
2005-04-17 02:20:36 +04:00
/* sector count, 32-bit */
2006-11-20 05:15:47 +03:00
ATA_SCSI_RBUF_SET ( 0 , last_lba > > ( 8 * 3 ) ) ;
ATA_SCSI_RBUF_SET ( 1 , last_lba > > ( 8 * 2 ) ) ;
ATA_SCSI_RBUF_SET ( 2 , last_lba > > ( 8 * 1 ) ) ;
ATA_SCSI_RBUF_SET ( 3 , last_lba ) ;
2005-04-17 02:20:36 +04:00
/* sector size */
2006-11-20 05:15:47 +03:00
ATA_SCSI_RBUF_SET ( 6 , ATA_SECT_SIZE > > 8 ) ;
ATA_SCSI_RBUF_SET ( 7 , ATA_SECT_SIZE ) ;
2005-04-17 02:20:36 +04:00
} else {
/* sector count, 64-bit */
2006-11-20 05:15:47 +03:00
ATA_SCSI_RBUF_SET ( 0 , last_lba > > ( 8 * 7 ) ) ;
ATA_SCSI_RBUF_SET ( 1 , last_lba > > ( 8 * 6 ) ) ;
ATA_SCSI_RBUF_SET ( 2 , last_lba > > ( 8 * 5 ) ) ;
ATA_SCSI_RBUF_SET ( 3 , last_lba > > ( 8 * 4 ) ) ;
ATA_SCSI_RBUF_SET ( 4 , last_lba > > ( 8 * 3 ) ) ;
ATA_SCSI_RBUF_SET ( 5 , last_lba > > ( 8 * 2 ) ) ;
ATA_SCSI_RBUF_SET ( 6 , last_lba > > ( 8 * 1 ) ) ;
ATA_SCSI_RBUF_SET ( 7 , last_lba ) ;
2005-04-17 02:20:36 +04:00
/* sector size */
2006-11-20 05:15:47 +03:00
ATA_SCSI_RBUF_SET ( 10 , ATA_SECT_SIZE > > 8 ) ;
ATA_SCSI_RBUF_SET ( 11 , ATA_SECT_SIZE ) ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
}
/**
* ata_scsiop_report_luns - Simulate REPORT LUNS command
* @ args : device IDENTIFY data / SCSI command of interest .
* @ rbuf : Response buffer , to which simulated SCSI cmd output is sent .
* @ buflen : Response buffer length .
*
* Simulate REPORT LUNS command .
*
* LOCKING :
2006-08-24 11:19:22 +04:00
* spin_lock_irqsave ( host lock )
2005-04-17 02:20:36 +04:00
*/
unsigned int ata_scsiop_report_luns ( struct ata_scsi_args * args , u8 * rbuf ,
unsigned int buflen )
{
VPRINTK ( " ENTER \n " ) ;
rbuf [ 3 ] = 8 ; /* just one lun, LUN 0, size 8 bytes */
return 0 ;
}
2005-10-09 16:55:41 +04:00
/**
* ata_scsi_set_sense - Set SCSI sense data and status
* @ cmd : SCSI request to be handled
* @ sk : SCSI - defined sense key
* @ asc : SCSI - defined additional sense code
* @ ascq : SCSI - defined additional sense code qualifier
*
* Helper function that builds a valid fixed format , current
* response code and the given sense key ( sk ) , additional sense
* code ( asc ) and additional sense code qualifier ( ascq ) with
* a SCSI command status of % SAM_STAT_CHECK_CONDITION and
* DRIVER_SENSE set in the upper bits of scsi_cmnd : : result .
*
* LOCKING :
* Not required
*/
void ata_scsi_set_sense ( struct scsi_cmnd * cmd , u8 sk , u8 asc , u8 ascq )
{
cmd - > result = ( DRIVER_SENSE < < 24 ) | SAM_STAT_CHECK_CONDITION ;
cmd - > sense_buffer [ 0 ] = 0x70 ; /* fixed format, current */
cmd - > sense_buffer [ 2 ] = sk ;
cmd - > sense_buffer [ 7 ] = 18 - 8 ; /* additional sense length */
cmd - > sense_buffer [ 12 ] = asc ;
cmd - > sense_buffer [ 13 ] = ascq ;
}
2005-04-17 02:20:36 +04:00
/**
* ata_scsi_badcmd - End a SCSI request with an error
* @ cmd : SCSI request to be handled
* @ done : SCSI command completion function
* @ asc : SCSI - defined additional sense code
* @ ascq : SCSI - defined additional sense code qualifier
*
* Helper function that completes a SCSI command with
* % SAM_STAT_CHECK_CONDITION , with a sense key % ILLEGAL_REQUEST
* and the specified additional sense codes .
*
* LOCKING :
2006-08-24 11:19:22 +04:00
* spin_lock_irqsave ( host lock )
2005-04-17 02:20:36 +04:00
*/
void ata_scsi_badcmd ( struct scsi_cmnd * cmd , void ( * done ) ( struct scsi_cmnd * ) , u8 asc , u8 ascq )
{
DPRINTK ( " ENTER \n " ) ;
2005-10-09 17:09:35 +04:00
ata_scsi_set_sense ( cmd , ILLEGAL_REQUEST , asc , ascq ) ;
2005-04-17 02:20:36 +04:00
done ( cmd ) ;
}
2006-01-23 07:09:36 +03:00
static void atapi_sense_complete ( struct ata_queued_cmd * qc )
2005-10-06 01:09:16 +04:00
{
2006-04-02 13:51:53 +04:00
if ( qc - > err_mask & & ( ( qc - > err_mask & AC_ERR_DEV ) = = 0 ) ) {
2005-11-14 22:50:05 +03:00
/* FIXME: not quite right; we don't want the
* translation of taskfile registers into
* a sense descriptors , since that ' s only
* correct for ATA , not ATAPI
*/
2006-11-14 16:37:35 +03:00
ata_gen_passthru_sense ( qc ) ;
2006-04-02 13:51:53 +04:00
}
2005-10-06 01:09:16 +04:00
2005-11-14 22:50:05 +03:00
qc - > scsidone ( qc - > scsicmd ) ;
2006-01-23 07:09:36 +03:00
ata_qc_free ( qc ) ;
2005-11-14 22:50:05 +03:00
}
2005-10-06 01:09:16 +04:00
2005-11-14 22:50:05 +03:00
/* is it pointless to prefer PIO for "safety reasons"? */
static inline int ata_pio_use_silly ( struct ata_port * ap )
{
return ( ap - > flags & ATA_FLAG_PIO_DMA ) ;
}
static void atapi_request_sense ( struct ata_queued_cmd * qc )
{
struct ata_port * ap = qc - > ap ;
struct scsi_cmnd * cmd = qc - > scsicmd ;
DPRINTK ( " ATAPI request sense \n " ) ;
2005-10-06 01:09:16 +04:00
/* FIXME: is this needed? */
memset ( cmd - > sense_buffer , 0 , sizeof ( cmd - > sense_buffer ) ) ;
2005-11-14 22:50:05 +03:00
ap - > ops - > tf_read ( ap , & qc - > tf ) ;
/* fill these in, for the case where they are -not- overwritten */
cmd - > sense_buffer [ 0 ] = 0x70 ;
cmd - > sense_buffer [ 2 ] = qc - > tf . feature > > 4 ;
ata_qc_reinit ( qc ) ;
2005-10-06 01:09:16 +04:00
ata_sg_init_one ( qc , cmd - > sense_buffer , sizeof ( cmd - > sense_buffer ) ) ;
qc - > dma_dir = DMA_FROM_DEVICE ;
2006-02-12 17:32:58 +03:00
memset ( & qc - > cdb , 0 , qc - > dev - > cdb_len ) ;
2005-10-06 01:09:16 +04:00
qc - > cdb [ 0 ] = REQUEST_SENSE ;
qc - > cdb [ 4 ] = SCSI_SENSE_BUFFERSIZE ;
qc - > tf . flags | = ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE ;
qc - > tf . command = ATA_CMD_PACKET ;
2005-11-14 22:50:05 +03:00
if ( ata_pio_use_silly ( ap ) ) {
qc - > tf . protocol = ATA_PROT_ATAPI_DMA ;
qc - > tf . feature | = ATAPI_PKT_DMA ;
} else {
qc - > tf . protocol = ATA_PROT_ATAPI ;
qc - > tf . lbam = ( 8 * 1024 ) & 0xff ;
qc - > tf . lbah = ( 8 * 1024 ) > > 8 ;
}
2005-10-06 01:09:16 +04:00
qc - > nbytes = SCSI_SENSE_BUFFERSIZE ;
2005-11-14 22:50:05 +03:00
qc - > complete_fn = atapi_sense_complete ;
2005-10-06 01:09:16 +04:00
2006-03-31 15:41:11 +04:00
ata_qc_issue ( qc ) ;
2005-10-06 01:09:16 +04:00
DPRINTK ( " EXIT \n " ) ;
}
2006-01-23 07:09:36 +03:00
static void atapi_qc_complete ( struct ata_queued_cmd * qc )
2005-04-17 02:20:36 +04:00
{
struct scsi_cmnd * cmd = qc - > scsicmd ;
2005-12-05 10:38:02 +03:00
unsigned int err_mask = qc - > err_mask ;
2005-04-17 02:20:36 +04:00
2005-10-30 12:44:42 +03:00
VPRINTK ( " ENTER, err_mask 0x%X \n " , err_mask ) ;
2005-10-06 02:39:23 +04:00
2006-05-15 15:58:16 +04:00
/* handle completion from new EH */
if ( unlikely ( qc - > ap - > ops - > error_handler & &
( err_mask | | qc - > flags & ATA_QCFLAG_SENSE_VALID ) ) ) {
if ( ! ( qc - > flags & ATA_QCFLAG_SENSE_VALID ) ) {
/* FIXME: not quite right; we don't want the
* translation of taskfile registers into a
* sense descriptors , since that ' s only
* correct for ATA , not ATAPI
*/
2006-11-14 16:37:35 +03:00
ata_gen_passthru_sense ( qc ) ;
2006-05-15 15:58:16 +04:00
}
2006-08-08 09:08:59 +04:00
/* SCSI EH automatically locks door if sdev->locked is
* set . Sometimes door lock request continues to
* fail , for example , when no media is present . This
* creates a loop - SCSI EH issues door lock which
* fails and gets invoked again to acquire sense data
* for the failed command .
*
* If door lock fails , always clear sdev - > locked to
* avoid this infinite loop .
*/
if ( qc - > cdb [ 0 ] = = ALLOW_MEDIUM_REMOVAL )
qc - > dev - > sdev - > locked = 0 ;
2006-05-15 15:58:16 +04:00
qc - > scsicmd - > result = SAM_STAT_CHECK_CONDITION ;
qc - > scsidone ( cmd ) ;
ata_qc_free ( qc ) ;
return ;
}
/* successful completion or old EH failure path */
2005-10-30 12:44:42 +03:00
if ( unlikely ( err_mask & AC_ERR_DEV ) ) {
2005-04-17 02:20:36 +04:00
cmd - > result = SAM_STAT_CHECK_CONDITION ;
2005-11-14 22:50:05 +03:00
atapi_request_sense ( qc ) ;
2006-01-23 07:09:36 +03:00
return ;
2006-04-02 13:51:53 +04:00
} else if ( unlikely ( err_mask ) ) {
2005-10-30 12:44:42 +03:00
/* FIXME: not quite right; we don't want the
* translation of taskfile registers into
* a sense descriptors , since that ' s only
* correct for ATA , not ATAPI
*/
2006-11-14 16:37:35 +03:00
ata_gen_passthru_sense ( qc ) ;
2006-04-02 13:51:53 +04:00
} else {
2005-04-17 02:20:36 +04:00
u8 * scsicmd = cmd - > cmnd ;
2005-12-22 00:35:44 +03:00
if ( ( scsicmd [ 0 ] = = INQUIRY ) & & ( ( scsicmd [ 1 ] & 0x03 ) = = 0 ) ) {
2005-04-17 02:20:36 +04:00
u8 * buf = NULL ;
unsigned int buflen ;
buflen = ata_scsi_rbuf_get ( cmd , & buf ) ;
2005-10-05 23:02:14 +04:00
/* ATAPI devices typically report zero for their SCSI version,
* and sometimes deviate from the spec WRT response data
* format . If SCSI version is reported as zero like normal ,
* then we make the following fixups : 1 ) Fake MMC - 5 version ,
* to indicate to the Linux scsi midlayer this is a modern
* device . 2 ) Ensure response data format / ATAPI information
* are always correct .
*/
if ( buf [ 2 ] = = 0 ) {
buf [ 2 ] = 0x5 ;
buf [ 3 ] = 0x32 ;
}
2005-04-17 02:20:36 +04:00
ata_scsi_rbuf_put ( cmd , buf ) ;
}
2005-10-05 23:02:14 +04:00
2005-04-17 02:20:36 +04:00
cmd - > result = SAM_STAT_GOOD ;
}
qc - > scsidone ( cmd ) ;
2006-01-23 07:09:36 +03:00
ata_qc_free ( qc ) ;
2005-04-17 02:20:36 +04:00
}
/**
* atapi_xlat - Initialize PACKET taskfile
* @ qc : command structure to be initialized
*
* LOCKING :
2006-08-24 11:19:22 +04:00
* spin_lock_irqsave ( host lock )
2005-04-17 02:20:36 +04:00
*
* RETURNS :
* Zero on success , non - zero on failure .
*/
2006-12-17 04:45:57 +03:00
static unsigned int atapi_xlat ( struct ata_queued_cmd * qc )
2005-04-17 02:20:36 +04:00
{
2006-12-17 04:45:08 +03:00
struct scsi_cmnd * scmd = qc - > scsicmd ;
2005-04-17 02:20:36 +04:00
struct ata_device * dev = qc - > dev ;
int using_pio = ( dev - > flags & ATA_DFLAG_PIO ) ;
2006-12-17 04:45:08 +03:00
int nodata = ( scmd - > sc_data_direction = = DMA_NONE ) ;
2005-04-17 02:20:36 +04:00
if ( ! using_pio )
/* Check whether ATAPI DMA is safe */
if ( ata_check_atapi_dma ( qc ) )
using_pio = 1 ;
2006-12-17 04:46:33 +03:00
memset ( qc - > cdb , 0 , dev - > cdb_len ) ;
memcpy ( qc - > cdb , scmd - > cmnd , scmd - > cmd_len ) ;
2005-04-17 02:20:36 +04:00
qc - > complete_fn = atapi_qc_complete ;
qc - > tf . flags | = ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE ;
2006-12-17 04:45:08 +03:00
if ( scmd - > sc_data_direction = = DMA_TO_DEVICE ) {
2005-04-17 02:20:36 +04:00
qc - > tf . flags | = ATA_TFLAG_WRITE ;
DPRINTK ( " direction: write \n " ) ;
}
qc - > tf . command = ATA_CMD_PACKET ;
/* no data, or PIO data xfer */
if ( using_pio | | nodata ) {
if ( nodata )
qc - > tf . protocol = ATA_PROT_ATAPI_NODATA ;
else
qc - > tf . protocol = ATA_PROT_ATAPI ;
qc - > tf . lbam = ( 8 * 1024 ) & 0xff ;
qc - > tf . lbah = ( 8 * 1024 ) > > 8 ;
}
/* DMA data xfer */
else {
qc - > tf . protocol = ATA_PROT_ATAPI_DMA ;
qc - > tf . feature | = ATAPI_PKT_DMA ;
2006-12-17 04:45:08 +03:00
if ( atapi_dmadir & & ( scmd - > sc_data_direction ! = DMA_TO_DEVICE ) )
2006-04-04 06:57:18 +04:00
/* some SATA bridges need us to indicate data xfer direction */
2005-04-17 02:20:36 +04:00
qc - > tf . feature | = ATAPI_DMADIR ;
}
2006-12-17 04:45:08 +03:00
qc - > nbytes = scmd - > request_bufflen ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2006-05-31 13:27:34 +04:00
static struct ata_device * ata_find_dev ( struct ata_port * ap , int id )
{
if ( likely ( id < ATA_MAX_DEVICES ) )
return & ap - > device [ id ] ;
return NULL ;
}
static struct ata_device * __ata_scsi_find_dev ( struct ata_port * ap ,
const struct scsi_device * scsidev )
{
/* skip commands not addressed to targets we simulate */
if ( unlikely ( scsidev - > channel | | scsidev - > lun ) )
return NULL ;
return ata_find_dev ( ap , scsidev - > id ) ;
}
2006-06-12 23:54:17 +04:00
/**
* ata_scsi_dev_enabled - determine if device is enabled
* @ dev : ATA device
*
* Determine if commands should be sent to the specified device .
*
* LOCKING :
2006-08-24 11:19:22 +04:00
* spin_lock_irqsave ( host lock )
2006-06-12 23:54:17 +04:00
*
* RETURNS :
* 0 if commands are not allowed / 1 if commands are allowed
*/
static int ata_scsi_dev_enabled ( struct ata_device * dev )
{
if ( unlikely ( ! ata_dev_enabled ( dev ) ) )
return 0 ;
if ( ! atapi_enabled | | ( dev - > ap - > flags & ATA_FLAG_NO_ATAPI ) ) {
if ( unlikely ( dev - > class = = ATA_DEV_ATAPI ) ) {
ata_dev_printk ( dev , KERN_WARNING ,
" WARNING: ATAPI is %s, device ignored. \n " ,
atapi_enabled ? " not supported with this driver " : " disabled " ) ;
return 0 ;
}
}
return 1 ;
}
2005-04-17 02:20:36 +04:00
/**
* ata_scsi_find_dev - lookup ata_device from scsi_cmnd
* @ ap : ATA port to which the device is attached
* @ scsidev : SCSI device from which we derive the ATA device
*
* Given various information provided in struct scsi_cmnd ,
* map that onto an ATA bus , and using that mapping
* determine which ata_device is associated with the
* SCSI command to be sent .
*
* LOCKING :
2006-08-24 11:19:22 +04:00
* spin_lock_irqsave ( host lock )
2005-04-17 02:20:36 +04:00
*
* RETURNS :
* Associated ATA device , or % NULL if not found .
*/
static struct ata_device *
2005-10-22 22:27:05 +04:00
ata_scsi_find_dev ( struct ata_port * ap , const struct scsi_device * scsidev )
2005-04-17 02:20:36 +04:00
{
2006-05-31 13:27:34 +04:00
struct ata_device * dev = __ata_scsi_find_dev ( ap , scsidev ) ;
2005-04-17 02:20:36 +04:00
2006-06-12 23:54:17 +04:00
if ( unlikely ( ! dev | | ! ata_scsi_dev_enabled ( dev ) ) )
2005-04-17 02:20:36 +04:00
return NULL ;
return dev ;
}
2005-05-12 23:45:22 +04:00
/*
* ata_scsi_map_proto - Map pass - thru protocol value to taskfile value .
* @ byte1 : Byte 1 from pass - thru CDB .
*
* RETURNS :
* ATA_PROT_UNKNOWN if mapping failed / unimplemented , protocol otherwise .
*/
static u8
ata_scsi_map_proto ( u8 byte1 )
{
switch ( ( byte1 & 0x1e ) > > 1 ) {
case 3 : /* Non-data */
return ATA_PROT_NODATA ;
case 6 : /* DMA */
return ATA_PROT_DMA ;
case 4 : /* PIO Data-in */
case 5 : /* PIO Data-out */
return ATA_PROT_PIO ;
case 10 : /* Device Reset */
case 0 : /* Hard Reset */
case 1 : /* SRST */
case 2 : /* Bus Idle */
case 7 : /* Packet */
case 8 : /* DMA Queued */
case 9 : /* Device Diagnostic */
case 11 : /* UDMA Data-in */
case 12 : /* UDMA Data-Out */
case 13 : /* FPDMA */
default : /* Reserved */
break ;
}
return ATA_PROT_UNKNOWN ;
}
/**
* ata_scsi_pass_thru - convert ATA pass - thru CDB to taskfile
* @ qc : command structure to be initialized
*
* Handles either 12 or 16 - byte versions of the CDB .
*
* RETURNS :
* Zero on success , non - zero on failure .
*/
2006-12-17 04:45:57 +03:00
static unsigned int ata_scsi_pass_thru ( struct ata_queued_cmd * qc )
2005-05-12 23:45:22 +04:00
{
struct ata_taskfile * tf = & ( qc - > tf ) ;
2006-12-17 04:45:08 +03:00
struct scsi_cmnd * scmd = qc - > scsicmd ;
2006-05-22 19:55:11 +04:00
struct ata_device * dev = qc - > dev ;
2006-12-17 04:45:57 +03:00
const u8 * cdb = scmd - > cmnd ;
2005-05-12 23:45:22 +04:00
2006-12-17 04:45:08 +03:00
if ( ( tf - > protocol = ata_scsi_map_proto ( cdb [ 1 ] ) ) = = ATA_PROT_UNKNOWN )
2005-12-02 05:49:11 +03:00
goto invalid_fld ;
2006-05-24 09:53:39 +04:00
2006-05-22 19:55:11 +04:00
/* We may not issue DMA commands if no DMA mode is set */
if ( tf - > protocol = = ATA_PROT_DMA & & dev - > dma_mode = = 0 )
goto invalid_fld ;
2005-05-12 23:45:22 +04:00
2006-12-17 04:45:08 +03:00
if ( cdb [ 1 ] & 0xe0 )
2006-03-16 12:59:22 +03:00
/* PIO multi not supported yet */
goto invalid_fld ;
2005-05-12 23:45:22 +04:00
/*
* 12 and 16 byte CDBs use different offsets to
* provide the various register values .
*/
2006-12-17 04:45:08 +03:00
if ( cdb [ 0 ] = = ATA_16 ) {
2005-05-12 23:45:22 +04:00
/*
* 16 - byte CDB - may contain extended commands .
*
* If that is the case , copy the upper byte register values .
*/
2006-12-17 04:45:08 +03:00
if ( cdb [ 1 ] & 0x01 ) {
tf - > hob_feature = cdb [ 3 ] ;
tf - > hob_nsect = cdb [ 5 ] ;
tf - > hob_lbal = cdb [ 7 ] ;
tf - > hob_lbam = cdb [ 9 ] ;
tf - > hob_lbah = cdb [ 11 ] ;
2005-05-12 23:45:22 +04:00
tf - > flags | = ATA_TFLAG_LBA48 ;
} else
tf - > flags & = ~ ATA_TFLAG_LBA48 ;
/*
* Always copy low byte , device and command registers .
*/
2006-12-17 04:45:08 +03:00
tf - > feature = cdb [ 4 ] ;
tf - > nsect = cdb [ 6 ] ;
tf - > lbal = cdb [ 8 ] ;
tf - > lbam = cdb [ 10 ] ;
tf - > lbah = cdb [ 12 ] ;
tf - > device = cdb [ 13 ] ;
tf - > command = cdb [ 14 ] ;
2005-05-12 23:45:22 +04:00
} else {
/*
* 12 - byte CDB - incapable of extended commands .
*/
tf - > flags & = ~ ATA_TFLAG_LBA48 ;
2006-12-17 04:45:08 +03:00
tf - > feature = cdb [ 3 ] ;
tf - > nsect = cdb [ 4 ] ;
tf - > lbal = cdb [ 5 ] ;
tf - > lbam = cdb [ 6 ] ;
tf - > lbah = cdb [ 7 ] ;
tf - > device = cdb [ 8 ] ;
tf - > command = cdb [ 9 ] ;
2005-05-12 23:45:22 +04:00
}
2005-11-14 00:22:06 +03:00
/*
* If slave is possible , enforce correct master / slave bit
*/
if ( qc - > ap - > flags & ATA_FLAG_SLAVE_POSS )
tf - > device = qc - > dev - > devno ?
tf - > device | ATA_DEV1 : tf - > device & ~ ATA_DEV1 ;
2005-05-12 23:45:22 +04:00
2007-03-16 17:22:26 +03:00
/* READ/WRITE LONG use a non-standard sect_size */
qc - > sect_size = ATA_SECT_SIZE ;
switch ( tf - > command ) {
case ATA_CMD_READ_LONG :
case ATA_CMD_READ_LONG_ONCE :
case ATA_CMD_WRITE_LONG :
case ATA_CMD_WRITE_LONG_ONCE :
if ( tf - > protocol ! = ATA_PROT_PIO | | tf - > nsect ! = 1 )
goto invalid_fld ;
qc - > sect_size = scmd - > request_bufflen ;
}
2005-05-12 23:45:22 +04:00
/*
* Filter SET_FEATURES - XFER MODE command - - otherwise ,
* SET_FEATURES - XFER MODE must be preceded / succeeded
* by an update to hardware - specific registers for each
* controller ( i . e . the reason for - > set_piomode ( ) ,
* - > set_dmamode ( ) , and - > post_set_mode ( ) hooks ) .
*/
if ( ( tf - > command = = ATA_CMD_SET_FEATURES )
& & ( tf - > feature = = SETFEATURES_XFER ) )
2005-12-02 05:49:11 +03:00
goto invalid_fld ;
2005-05-12 23:45:22 +04:00
/*
* Set flags so that all registers will be written ,
* and pass on write indication ( used for PIO / DMA
* setup . )
*/
tf - > flags | = ( ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE ) ;
2006-12-17 04:45:08 +03:00
if ( scmd - > sc_data_direction = = DMA_TO_DEVICE )
2005-05-12 23:45:22 +04:00
tf - > flags | = ATA_TFLAG_WRITE ;
/*
* Set transfer length .
*
* TODO : find out if we need to do more here to
* cover scatter / gather case .
*/
2007-01-03 11:30:39 +03:00
qc - > nbytes = scmd - > request_bufflen ;
2005-05-12 23:45:22 +04:00
2006-05-15 15:57:40 +04:00
/* request result TF */
qc - > flags | = ATA_QCFLAG_RESULT_TF ;
2005-05-12 23:45:22 +04:00
return 0 ;
2005-12-02 05:49:11 +03:00
invalid_fld :
2006-12-17 04:45:08 +03:00
ata_scsi_set_sense ( scmd , ILLEGAL_REQUEST , 0x24 , 0x00 ) ;
2005-12-02 05:49:11 +03:00
/* "Invalid field in cdb" */
return 1 ;
2005-05-12 23:45:22 +04:00
}
2005-04-17 02:20:36 +04:00
/**
* ata_get_xlat_func - check if SCSI to ATA translation is possible
* @ dev : ATA device
* @ cmd : SCSI command opcode to consider
*
* Look up the SCSI command given , and determine whether the
* SCSI command is to be translated or simulated .
*
* RETURNS :
* Pointer to translation function if possible , % NULL if not .
*/
static inline ata_xlat_func_t ata_get_xlat_func ( struct ata_device * dev , u8 cmd )
{
switch ( cmd ) {
case READ_6 :
case READ_10 :
case READ_16 :
case WRITE_6 :
case WRITE_10 :
case WRITE_16 :
return ata_scsi_rw_xlat ;
case SYNCHRONIZE_CACHE :
if ( ata_try_flush_cache ( dev ) )
return ata_scsi_flush_xlat ;
break ;
case VERIFY :
case VERIFY_16 :
return ata_scsi_verify_xlat ;
2005-05-12 23:45:22 +04:00
case ATA_12 :
case ATA_16 :
return ata_scsi_pass_thru ;
2005-08-30 03:01:43 +04:00
2005-08-11 11:35:53 +04:00
case START_STOP :
return ata_scsi_start_stop_xlat ;
2005-04-17 02:20:36 +04:00
}
return NULL ;
}
/**
* ata_scsi_dump_cdb - dump SCSI command contents to dmesg
* @ ap : ATA port to which the command was being sent
* @ cmd : SCSI command to dump
*
* Prints the contents of a SCSI command via printk ( ) .
*/
static inline void ata_scsi_dump_cdb ( struct ata_port * ap ,
struct scsi_cmnd * cmd )
{
# ifdef ATA_DEBUG
struct scsi_device * scsidev = cmd - > device ;
u8 * scsicmd = cmd - > cmnd ;
DPRINTK ( " CDB (%u:%d,%d,%d) %02x %02x %02x %02x %02x %02x %02x %02x %02x \n " ,
2007-02-20 19:06:51 +03:00
ap - > print_id ,
2005-04-17 02:20:36 +04:00
scsidev - > channel , scsidev - > id , scsidev - > lun ,
scsicmd [ 0 ] , scsicmd [ 1 ] , scsicmd [ 2 ] , scsicmd [ 3 ] ,
scsicmd [ 4 ] , scsicmd [ 5 ] , scsicmd [ 6 ] , scsicmd [ 7 ] ,
scsicmd [ 8 ] ) ;
# endif
}
2006-12-17 04:45:08 +03:00
static inline int __ata_scsi_queuecmd ( struct scsi_cmnd * scmd ,
2006-05-15 16:03:39 +04:00
void ( * done ) ( struct scsi_cmnd * ) ,
struct ata_device * dev )
2006-03-24 02:30:02 +03:00
{
2006-05-15 16:03:39 +04:00
int rc = 0 ;
2007-02-02 20:36:25 +03:00
if ( unlikely ( ! scmd - > cmd_len | | scmd - > cmd_len > dev - > cdb_len ) ) {
DPRINTK ( " bad CDB len=%u, max=%u \n " ,
scmd - > cmd_len , dev - > cdb_len ) ;
2006-12-17 04:46:33 +03:00
scmd - > result = DID_ERROR < < 16 ;
done ( scmd ) ;
return 0 ;
}
2006-03-24 02:30:02 +03:00
if ( dev - > class = = ATA_DEV_ATA ) {
ata_xlat_func_t xlat_func = ata_get_xlat_func ( dev ,
2006-12-17 04:45:08 +03:00
scmd - > cmnd [ 0 ] ) ;
2006-03-24 02:30:02 +03:00
if ( xlat_func )
2006-12-17 04:45:08 +03:00
rc = ata_scsi_translate ( dev , scmd , done , xlat_func ) ;
2006-03-24 02:30:02 +03:00
else
2006-12-17 04:45:08 +03:00
ata_scsi_simulate ( dev , scmd , done ) ;
2006-03-24 02:30:02 +03:00
} else
2006-12-17 04:45:08 +03:00
rc = ata_scsi_translate ( dev , scmd , done , atapi_xlat ) ;
2006-05-15 16:03:39 +04:00
return rc ;
2006-03-24 02:30:02 +03:00
}
2005-04-17 02:20:36 +04:00
/**
* ata_scsi_queuecmd - Issue SCSI cdb to libata - managed device
* @ cmd : SCSI command to be sent
* @ done : Completion function , called when command is complete
*
* In some cases , this function translates SCSI commands into
* ATA taskfiles , and queues the taskfiles to be sent to
* hardware . In other cases , this function simulates a
* SCSI device by evaluating and responding to certain
* SCSI commands . This creates the overall effect of
* ATA and ATAPI devices appearing as SCSI devices .
*
* LOCKING :
2006-08-24 11:19:22 +04:00
* Releases scsi - layer - held lock , and obtains host lock .
2005-04-17 02:20:36 +04:00
*
* RETURNS :
2006-05-15 16:03:39 +04:00
* Return value from __ata_scsi_queuecmd ( ) if @ cmd can be queued ,
* 0 otherwise .
2005-04-17 02:20:36 +04:00
*/
int ata_scsi_queuecmd ( struct scsi_cmnd * cmd , void ( * done ) ( struct scsi_cmnd * ) )
{
struct ata_port * ap ;
struct ata_device * dev ;
struct scsi_device * scsidev = cmd - > device ;
2005-10-31 07:31:48 +03:00
struct Scsi_Host * shost = scsidev - > host ;
2006-05-15 16:03:39 +04:00
int rc = 0 ;
2005-04-17 02:20:36 +04:00
2006-04-11 21:12:34 +04:00
ap = ata_shost_to_port ( shost ) ;
2005-10-31 07:31:48 +03:00
spin_unlock ( shost - > host_lock ) ;
2006-06-23 07:46:10 +04:00
spin_lock ( ap - > lock ) ;
2005-04-17 02:20:36 +04:00
ata_scsi_dump_cdb ( ap , cmd ) ;
dev = ata_scsi_find_dev ( ap , scsidev ) ;
2006-03-24 02:30:02 +03:00
if ( likely ( dev ) )
2006-05-15 16:03:39 +04:00
rc = __ata_scsi_queuecmd ( cmd , done , dev ) ;
2006-03-24 02:30:02 +03:00
else {
2005-04-17 02:20:36 +04:00
cmd - > result = ( DID_BAD_TARGET < < 16 ) ;
done ( cmd ) ;
}
2006-06-23 07:46:10 +04:00
spin_unlock ( ap - > lock ) ;
2005-10-31 07:31:48 +03:00
spin_lock ( shost - > host_lock ) ;
2006-05-15 16:03:39 +04:00
return rc ;
2005-04-17 02:20:36 +04:00
}
/**
* ata_scsi_simulate - simulate SCSI command on ATA device
2006-01-28 21:15:32 +03:00
* @ dev : the target device
2005-04-17 02:20:36 +04:00
* @ cmd : SCSI command being sent to device .
* @ done : SCSI command completion function .
*
* Interprets and directly executes a select list of SCSI commands
* that can be handled internally .
*
* LOCKING :
2006-08-24 11:19:22 +04:00
* spin_lock_irqsave ( host lock )
2005-04-17 02:20:36 +04:00
*/
2006-05-15 15:57:53 +04:00
void ata_scsi_simulate ( struct ata_device * dev , struct scsi_cmnd * cmd ,
2005-04-17 02:20:36 +04:00
void ( * done ) ( struct scsi_cmnd * ) )
{
struct ata_scsi_args args ;
2005-10-22 22:27:05 +04:00
const u8 * scsicmd = cmd - > cmnd ;
2005-04-17 02:20:36 +04:00
2006-01-06 11:56:18 +03:00
args . dev = dev ;
args . id = dev - > id ;
2005-04-17 02:20:36 +04:00
args . cmd = cmd ;
args . done = done ;
switch ( scsicmd [ 0 ] ) {
/* no-op's, complete with success */
case SYNCHRONIZE_CACHE :
case REZERO_UNIT :
case SEEK_6 :
case SEEK_10 :
case TEST_UNIT_READY :
case FORMAT_UNIT : /* FIXME: correct? */
case SEND_DIAGNOSTIC : /* FIXME: correct? */
ata_scsi_rbuf_fill ( & args , ata_scsiop_noop ) ;
break ;
case INQUIRY :
if ( scsicmd [ 1 ] & 2 ) /* is CmdDt set? */
2005-10-09 17:09:35 +04:00
ata_scsi_invalid_field ( cmd , done ) ;
2005-04-17 02:20:36 +04:00
else if ( ( scsicmd [ 1 ] & 1 ) = = 0 ) /* is EVPD clear? */
ata_scsi_rbuf_fill ( & args , ata_scsiop_inq_std ) ;
else if ( scsicmd [ 2 ] = = 0x00 )
ata_scsi_rbuf_fill ( & args , ata_scsiop_inq_00 ) ;
else if ( scsicmd [ 2 ] = = 0x80 )
ata_scsi_rbuf_fill ( & args , ata_scsiop_inq_80 ) ;
else if ( scsicmd [ 2 ] = = 0x83 )
ata_scsi_rbuf_fill ( & args , ata_scsiop_inq_83 ) ;
else
2005-10-09 17:09:35 +04:00
ata_scsi_invalid_field ( cmd , done ) ;
2005-04-17 02:20:36 +04:00
break ;
case MODE_SENSE :
case MODE_SENSE_10 :
ata_scsi_rbuf_fill ( & args , ata_scsiop_mode_sense ) ;
break ;
case MODE_SELECT : /* unconditionally return */
case MODE_SELECT_10 : /* bad-field-in-cdb */
2005-10-09 17:09:35 +04:00
ata_scsi_invalid_field ( cmd , done ) ;
2005-04-17 02:20:36 +04:00
break ;
case READ_CAPACITY :
ata_scsi_rbuf_fill ( & args , ata_scsiop_read_cap ) ;
break ;
case SERVICE_ACTION_IN :
if ( ( scsicmd [ 1 ] & 0x1f ) = = SAI_READ_CAPACITY_16 )
ata_scsi_rbuf_fill ( & args , ata_scsiop_read_cap ) ;
else
2005-10-09 17:09:35 +04:00
ata_scsi_invalid_field ( cmd , done ) ;
2005-04-17 02:20:36 +04:00
break ;
case REPORT_LUNS :
ata_scsi_rbuf_fill ( & args , ata_scsiop_report_luns ) ;
break ;
2005-05-12 23:45:22 +04:00
/* mandatory commands we haven't implemented yet */
2005-04-17 02:20:36 +04:00
case REQUEST_SENSE :
/* all other commands */
default :
2005-10-09 17:09:35 +04:00
ata_scsi_set_sense ( cmd , ILLEGAL_REQUEST , 0x20 , 0x0 ) ;
/* "Invalid command operation code" */
done ( cmd ) ;
2005-04-17 02:20:36 +04:00
break ;
}
}
2005-10-03 23:55:19 +04:00
void ata_scsi_scan_host ( struct ata_port * ap )
{
unsigned int i ;
2006-04-02 13:51:52 +04:00
if ( ap - > flags & ATA_FLAG_DISABLED )
2005-10-03 23:55:19 +04:00
return ;
2005-10-04 05:36:41 +04:00
for ( i = 0 ; i < ATA_MAX_DEVICES ; i + + ) {
2006-05-31 13:27:40 +04:00
struct ata_device * dev = & ap - > device [ i ] ;
struct scsi_device * sdev ;
if ( ! ata_dev_enabled ( dev ) | | dev - > sdev )
continue ;
2005-10-04 05:36:41 +04:00
2006-08-24 11:19:22 +04:00
sdev = __scsi_add_device ( ap - > scsi_host , 0 , i , 0 , NULL ) ;
2006-05-31 13:27:40 +04:00
if ( ! IS_ERR ( sdev ) ) {
dev - > sdev = sdev ;
scsi_device_put ( sdev ) ;
}
2005-10-04 05:36:41 +04:00
}
2005-10-03 23:55:19 +04:00
}
2006-05-31 13:28:01 +04:00
/**
* ata_scsi_offline_dev - offline attached SCSI device
* @ dev : ATA device to offline attached SCSI device for
*
* This function is called from ata_eh_hotplug ( ) and responsible
* for taking the SCSI device attached to @ dev offline . This
2006-08-24 11:19:22 +04:00
* function is called with host lock which protects dev - > sdev
2006-05-31 13:28:01 +04:00
* against clearing .
*
* LOCKING :
2006-08-24 11:19:22 +04:00
* spin_lock_irqsave ( host lock )
2006-05-31 13:28:01 +04:00
*
* RETURNS :
* 1 if attached SCSI device exists , 0 otherwise .
*/
int ata_scsi_offline_dev ( struct ata_device * dev )
{
if ( dev - > sdev ) {
scsi_device_set_state ( dev - > sdev , SDEV_OFFLINE ) ;
return 1 ;
}
return 0 ;
}
2006-05-31 13:28:05 +04:00
/**
* ata_scsi_remove_dev - remove attached SCSI device
* @ dev : ATA device to remove attached SCSI device for
*
* This function is called from ata_eh_scsi_hotplug ( ) and
* responsible for removing the SCSI device attached to @ dev .
*
* LOCKING :
* Kernel thread context ( may sleep ) .
*/
static void ata_scsi_remove_dev ( struct ata_device * dev )
{
struct ata_port * ap = dev - > ap ;
struct scsi_device * sdev ;
unsigned long flags ;
/* Alas, we need to grab scan_mutex to ensure SCSI device
* state doesn ' t change underneath us and thus
* scsi_device_get ( ) always succeeds . The mutex locking can
* be removed if there is __scsi_device_get ( ) interface which
* increments reference counts regardless of device state .
*/
2006-08-24 11:19:22 +04:00
mutex_lock ( & ap - > scsi_host - > scan_mutex ) ;
2006-06-23 07:46:10 +04:00
spin_lock_irqsave ( ap - > lock , flags ) ;
2006-05-31 13:28:05 +04:00
2006-08-24 11:19:22 +04:00
/* clearing dev->sdev is protected by host lock */
2006-05-31 13:28:05 +04:00
sdev = dev - > sdev ;
dev - > sdev = NULL ;
if ( sdev ) {
/* If user initiated unplug races with us, sdev can go
2006-08-24 11:19:22 +04:00
* away underneath us after the host lock and
2006-05-31 13:28:05 +04:00
* scan_mutex are released . Hold onto it .
*/
if ( scsi_device_get ( sdev ) = = 0 ) {
/* The following ensures the attached sdev is
* offline on return from ata_scsi_offline_dev ( )
* regardless it wins or loses the race
* against this function .
*/
scsi_device_set_state ( sdev , SDEV_OFFLINE ) ;
} else {
WARN_ON ( 1 ) ;
sdev = NULL ;
}
}
2006-06-23 07:46:10 +04:00
spin_unlock_irqrestore ( ap - > lock , flags ) ;
2006-08-24 11:19:22 +04:00
mutex_unlock ( & ap - > scsi_host - > scan_mutex ) ;
2006-05-31 13:28:05 +04:00
if ( sdev ) {
ata_dev_printk ( dev , KERN_INFO , " detaching (SCSI %s) \n " ,
sdev - > sdev_gendev . bus_id ) ;
scsi_remove_device ( sdev ) ;
scsi_device_put ( sdev ) ;
}
}
/**
* ata_scsi_hotplug - SCSI part of hotplug
2006-11-22 17:55:48 +03:00
* @ work : Pointer to ATA port to perform SCSI hotplug on
2006-05-31 13:28:05 +04:00
*
* Perform SCSI part of hotplug . It ' s executed from a separate
* workqueue after EH completes . This is necessary because SCSI
* hot plugging requires working EH and hot unplugging is
* synchronized with hot plugging with a mutex .
*
* LOCKING :
* Kernel thread context ( may sleep ) .
*/
2006-11-22 17:55:48 +03:00
void ata_scsi_hotplug ( struct work_struct * work )
2006-05-31 13:28:05 +04:00
{
2006-11-22 17:55:48 +03:00
struct ata_port * ap =
container_of ( work , struct ata_port , hotplug_task . work ) ;
2006-05-31 13:28:05 +04:00
int i ;
2006-06-28 20:29:30 +04:00
if ( ap - > pflags & ATA_PFLAG_UNLOADING ) {
2006-05-31 13:28:05 +04:00
DPRINTK ( " ENTER/EXIT - unloading \n " ) ;
return ;
}
DPRINTK ( " ENTER \n " ) ;
/* unplug detached devices */
for ( i = 0 ; i < ATA_MAX_DEVICES ; i + + ) {
struct ata_device * dev = & ap - > device [ i ] ;
unsigned long flags ;
if ( ! ( dev - > flags & ATA_DFLAG_DETACHED ) )
continue ;
2006-06-23 07:46:10 +04:00
spin_lock_irqsave ( ap - > lock , flags ) ;
2006-05-31 13:28:05 +04:00
dev - > flags & = ~ ATA_DFLAG_DETACHED ;
2006-06-23 07:46:10 +04:00
spin_unlock_irqrestore ( ap - > lock , flags ) ;
2006-05-31 13:28:05 +04:00
ata_scsi_remove_dev ( dev ) ;
}
/* scan for new ones */
ata_scsi_scan_host ( ap ) ;
/* If we scanned while EH was in progress, scan would have
* failed silently . Requeue if there are enabled but
* unattached devices .
*/
for ( i = 0 ; i < ATA_MAX_DEVICES ; i + + ) {
struct ata_device * dev = & ap - > device [ i ] ;
if ( ata_dev_enabled ( dev ) & & ! dev - > sdev ) {
2006-12-20 00:05:53 +03:00
queue_delayed_work ( ata_aux_wq , & ap - > hotplug_task ,
round_jiffies_relative ( HZ ) ) ;
2006-05-31 13:28:05 +04:00
break ;
}
}
DPRINTK ( " EXIT \n " ) ;
}
2006-05-31 13:28:07 +04:00
/**
* ata_scsi_user_scan - indication for user - initiated bus scan
* @ shost : SCSI host to scan
* @ channel : Channel to scan
* @ id : ID to scan
* @ lun : LUN to scan
*
* This function is called when user explicitly requests bus
* scan . Set probe pending flag and invoke EH .
*
* LOCKING :
* SCSI layer ( we don ' t care )
*
* RETURNS :
* Zero .
*/
static int ata_scsi_user_scan ( struct Scsi_Host * shost , unsigned int channel ,
unsigned int id , unsigned int lun )
{
struct ata_port * ap = ata_shost_to_port ( shost ) ;
unsigned long flags ;
int rc = 0 ;
if ( ! ap - > ops - > error_handler )
return - EOPNOTSUPP ;
if ( ( channel ! = SCAN_WILD_CARD & & channel ! = 0 ) | |
( lun ! = SCAN_WILD_CARD & & lun ! = 0 ) )
return - EINVAL ;
2006-06-23 07:46:10 +04:00
spin_lock_irqsave ( ap - > lock , flags ) ;
2006-05-31 13:28:07 +04:00
if ( id = = SCAN_WILD_CARD ) {
ap - > eh_info . probe_mask | = ( 1 < < ATA_MAX_DEVICES ) - 1 ;
ap - > eh_info . action | = ATA_EH_SOFTRESET ;
} else {
struct ata_device * dev = ata_find_dev ( ap , id ) ;
if ( dev ) {
ap - > eh_info . probe_mask | = 1 < < dev - > devno ;
ap - > eh_info . action | = ATA_EH_SOFTRESET ;
2006-07-03 11:07:26 +04:00
ap - > eh_info . flags | = ATA_EHI_RESUME_LINK ;
2006-05-31 13:28:07 +04:00
} else
rc = - EINVAL ;
}
2006-09-30 13:07:17 +04:00
if ( rc = = 0 ) {
2006-05-31 13:28:07 +04:00
ata_port_schedule_eh ( ap ) ;
2006-09-30 13:07:17 +04:00
spin_unlock_irqrestore ( ap - > lock , flags ) ;
ata_port_wait_eh ( ap ) ;
} else
spin_unlock_irqrestore ( ap - > lock , flags ) ;
2006-05-31 13:28:07 +04:00
return rc ;
}
2006-06-12 08:01:34 +04:00
/**
2006-06-12 17:51:14 +04:00
* ata_scsi_dev_rescan - initiate scsi_rescan_device ( )
2006-11-22 17:55:48 +03:00
* @ work : Pointer to ATA port to perform scsi_rescan_device ( )
2006-06-12 08:01:34 +04:00
*
2006-06-12 17:51:14 +04:00
* After ATA pass thru ( SAT ) commands are executed successfully ,
* libata need to propagate the changes to SCSI layer . This
* function must be executed from ata_aux_wq such that sdev
* attach / detach don ' t race with rescan .
2006-06-12 08:01:34 +04:00
*
2006-06-12 17:51:14 +04:00
* LOCKING :
* Kernel thread context ( may sleep ) .
2006-06-12 08:01:34 +04:00
*/
2006-11-22 17:55:48 +03:00
void ata_scsi_dev_rescan ( struct work_struct * work )
2006-06-12 08:01:34 +04:00
{
2006-11-22 17:55:48 +03:00
struct ata_port * ap =
container_of ( work , struct ata_port , scsi_rescan_task ) ;
2006-11-22 05:21:31 +03:00
unsigned long flags ;
2006-06-12 08:01:34 +04:00
unsigned int i ;
2006-11-22 05:21:31 +03:00
spin_lock_irqsave ( ap - > lock , flags ) ;
2006-06-12 08:01:34 +04:00
for ( i = 0 ; i < ATA_MAX_DEVICES ; i + + ) {
2006-11-22 05:21:31 +03:00
struct ata_device * dev = & ap - > device [ i ] ;
struct scsi_device * sdev = dev - > sdev ;
2006-06-12 08:01:34 +04:00
2006-11-22 05:21:31 +03:00
if ( ! ata_dev_enabled ( dev ) | | ! sdev )
continue ;
if ( scsi_device_get ( sdev ) )
continue ;
spin_unlock_irqrestore ( ap - > lock , flags ) ;
scsi_rescan_device ( & ( sdev - > sdev_gendev ) ) ;
scsi_device_put ( sdev ) ;
spin_lock_irqsave ( ap - > lock , flags ) ;
2006-06-12 08:01:34 +04:00
}
2006-11-22 05:21:31 +03:00
spin_unlock_irqrestore ( ap - > lock , flags ) ;
2006-06-12 08:01:34 +04:00
}
2006-08-07 23:27:31 +04:00
/**
* ata_sas_port_alloc - Allocate port for a SAS attached SATA device
2006-09-29 13:07:25 +04:00
* @ host : ATA host container for all SAS ports
2006-08-07 23:27:31 +04:00
* @ port_info : Information from low - level host driver
2006-08-24 11:19:22 +04:00
* @ shost : SCSI host that the scsi device is attached to
2006-08-07 23:27:31 +04:00
*
* LOCKING :
* PCI / etc . bus probe sem .
*
* RETURNS :
* ata_port pointer on success / NULL on failure .
*/
2006-08-24 11:19:22 +04:00
struct ata_port * ata_sas_port_alloc ( struct ata_host * host ,
2006-08-07 23:27:31 +04:00
struct ata_port_info * port_info ,
2006-08-24 11:19:22 +04:00
struct Scsi_Host * shost )
2006-08-07 23:27:31 +04:00
{
struct ata_port * ap = kzalloc ( sizeof ( * ap ) , GFP_KERNEL ) ;
struct ata_probe_ent * ent ;
if ( ! ap )
return NULL ;
2006-08-24 11:19:22 +04:00
ent = ata_probe_ent_alloc ( host - > dev , port_info ) ;
2006-08-07 23:27:31 +04:00
if ( ! ent ) {
kfree ( ap ) ;
return NULL ;
}
2006-08-24 11:19:22 +04:00
ata_port_init ( ap , host , ent , 0 ) ;
ap - > lock = shost - > host_lock ;
2007-02-17 20:24:37 +03:00
devm_kfree ( host - > dev , ent ) ;
2006-08-07 23:27:31 +04:00
return ap ;
}
EXPORT_SYMBOL_GPL ( ata_sas_port_alloc ) ;
/**
* ata_sas_port_start - Set port up for dma .
* @ ap : Port to initialize
*
* Called just after data structures for each port are
* initialized . Allocates DMA pad .
*
* May be used as the port_start ( ) entry in ata_port_operations .
*
* LOCKING :
* Inherited from caller .
*/
int ata_sas_port_start ( struct ata_port * ap )
{
return ata_pad_alloc ( ap , ap - > dev ) ;
}
EXPORT_SYMBOL_GPL ( ata_sas_port_start ) ;
/**
* ata_port_stop - Undo ata_sas_port_start ( )
* @ ap : Port to shut down
*
* Frees the DMA pad .
*
* May be used as the port_stop ( ) entry in ata_port_operations .
*
* LOCKING :
* Inherited from caller .
*/
void ata_sas_port_stop ( struct ata_port * ap )
{
ata_pad_free ( ap , ap - > dev ) ;
}
EXPORT_SYMBOL_GPL ( ata_sas_port_stop ) ;
/**
* ata_sas_port_init - Initialize a SATA device
* @ ap : SATA port to initialize
*
* LOCKING :
* PCI / etc . bus probe sem .
*
* RETURNS :
* Zero on success , non - zero on error .
*/
int ata_sas_port_init ( struct ata_port * ap )
{
int rc = ap - > ops - > port_start ( ap ) ;
if ( ! rc )
rc = ata_bus_probe ( ap ) ;
return rc ;
}
EXPORT_SYMBOL_GPL ( ata_sas_port_init ) ;
/**
* ata_sas_port_destroy - Destroy a SATA port allocated by ata_sas_port_alloc
* @ ap : SATA port to destroy
*
*/
void ata_sas_port_destroy ( struct ata_port * ap )
{
2007-01-20 10:00:28 +03:00
if ( ap - > ops - > port_stop )
ap - > ops - > port_stop ( ap ) ;
2006-08-07 23:27:31 +04:00
kfree ( ap ) ;
}
EXPORT_SYMBOL_GPL ( ata_sas_port_destroy ) ;
/**
* ata_sas_slave_configure - Default slave_config routine for libata devices
* @ sdev : SCSI device to configure
* @ ap : ATA port to which SCSI device is attached
*
* RETURNS :
* Zero .
*/
int ata_sas_slave_configure ( struct scsi_device * sdev , struct ata_port * ap )
{
ata_scsi_sdev_config ( sdev ) ;
ata_scsi_dev_config ( sdev , ap - > device ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( ata_sas_slave_configure ) ;
/**
* ata_sas_queuecmd - Issue SCSI cdb to libata - managed device
* @ cmd : SCSI command to be sent
* @ done : Completion function , called when command is complete
* @ ap : ATA port to which the command is being sent
*
* RETURNS :
2006-11-20 22:51:56 +03:00
* Return value from __ata_scsi_queuecmd ( ) if @ cmd can be queued ,
* 0 otherwise .
2006-08-07 23:27:31 +04:00
*/
int ata_sas_queuecmd ( struct scsi_cmnd * cmd , void ( * done ) ( struct scsi_cmnd * ) ,
struct ata_port * ap )
{
2006-11-20 22:51:56 +03:00
int rc = 0 ;
2006-08-07 23:27:31 +04:00
ata_scsi_dump_cdb ( ap , cmd ) ;
if ( likely ( ata_scsi_dev_enabled ( ap - > device ) ) )
2006-11-20 22:51:56 +03:00
rc = __ata_scsi_queuecmd ( cmd , done , ap - > device ) ;
2006-08-07 23:27:31 +04:00
else {
cmd - > result = ( DID_BAD_TARGET < < 16 ) ;
done ( cmd ) ;
}
2006-11-20 22:51:56 +03:00
return rc ;
2006-08-07 23:27:31 +04:00
}
EXPORT_SYMBOL_GPL ( ata_sas_queuecmd ) ;