2007-05-08 04:33:32 +04:00
/*
* SBP2 driver ( SCSI over IEEE1394 )
2006-12-20 03:58:40 +03:00
*
2007-02-06 22:49:39 +03:00
* Copyright ( C ) 2005 - 2007 Kristian Hoegsberg < krh @ bitplanet . net >
2006-12-20 03:58:40 +03:00
*
* 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 of the License , 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 ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
2007-05-08 04:33:32 +04:00
/*
* The basic structure of this driver is based on the old storage driver ,
2007-02-06 22:49:39 +03:00
* drivers / ieee1394 / sbp2 . c , originally written by
* James Goodwin < jamesg @ filanet . com >
* with later contributions and ongoing maintenance from
* Ben Collins < bcollins @ debian . org > ,
* Stefan Richter < stefanr @ s5r6 . in - berlin . de >
* and many others .
*/
2006-12-20 03:58:40 +03:00
# include <linux/kernel.h>
# include <linux/module.h>
2007-06-18 01:55:41 +04:00
# include <linux/moduleparam.h>
2006-12-28 14:46:54 +03:00
# include <linux/mod_devicetable.h>
2006-12-20 03:58:40 +03:00
# include <linux/device.h>
2006-12-28 01:49:23 +03:00
# include <linux/scatterlist.h>
2006-12-20 03:58:40 +03:00
# include <linux/dma-mapping.h>
2007-06-18 01:52:08 +04:00
# include <linux/blkdev.h>
2007-02-06 22:49:33 +03:00
# include <linux/timer.h>
2006-12-20 03:58:40 +03:00
# include <scsi/scsi.h>
# include <scsi/scsi_cmnd.h>
# include <scsi/scsi_dbg.h>
# include <scsi/scsi_device.h>
# include <scsi/scsi_host.h>
# include "fw-transaction.h"
# include "fw-topology.h"
# include "fw-device.h"
2007-06-18 01:55:41 +04:00
/*
* So far only bridges from Oxford Semiconductor are known to support
* concurrent logins . Depending on firmware , four or two concurrent logins
* are possible on OXFW911 and newer Oxsemi bridges .
*
* Concurrent logins are useful together with cluster filesystems .
*/
static int sbp2_param_exclusive_login = 1 ;
module_param_named ( exclusive_login , sbp2_param_exclusive_login , bool , 0644 ) ;
MODULE_PARM_DESC ( exclusive_login , " Exclusive login to sbp2 device "
" (default = Y, use N for concurrent initiators) " ) ;
2006-12-20 03:58:40 +03:00
/* I don't know why the SCSI stack doesn't define something like this... */
2007-05-08 04:33:34 +04:00
typedef void ( * scsi_done_fn_t ) ( struct scsi_cmnd * ) ;
2006-12-20 03:58:40 +03:00
static const char sbp2_driver_name [ ] = " sbp2 " ;
struct sbp2_device {
2007-03-15 00:34:58 +03:00
struct kref kref ;
2006-12-20 03:58:40 +03:00
struct fw_unit * unit ;
struct fw_address_handler address_handler ;
struct list_head orb_list ;
u64 management_agent_address ;
u64 command_block_agent_address ;
u32 workarounds ;
int login_id ;
2007-05-08 04:33:32 +04:00
/*
* We cache these addresses and only update them once we ' ve
2006-12-20 03:58:40 +03:00
* logged in or reconnected to the sbp2 device . That way , any
* IO to the device will automatically fail and get retried if
* it happens in a window where the device is not ready to
2007-05-08 04:33:32 +04:00
* handle it ( e . g . after a bus reset but before we reconnect ) .
*/
2006-12-20 03:58:40 +03:00
int node_id ;
int address_high ;
int generation ;
2007-02-06 22:49:34 +03:00
int retries ;
struct delayed_work work ;
2006-12-20 03:58:40 +03:00
} ;
# define SBP2_MAX_SG_ELEMENT_LENGTH 0xf000
# define SBP2_MAX_SECTORS 255 /* Max sectors supported */
2007-02-06 22:49:33 +03:00
# define SBP2_ORB_TIMEOUT 2000 /* Timeout in ms */
2006-12-20 03:58:40 +03:00
# define SBP2_ORB_NULL 0x80000000
# define SBP2_DIRECTION_TO_MEDIA 0x0
# define SBP2_DIRECTION_FROM_MEDIA 0x1
/* Unit directory keys */
# define SBP2_COMMAND_SET_SPECIFIER 0x38
# define SBP2_COMMAND_SET 0x39
# define SBP2_COMMAND_SET_REVISION 0x3b
# define SBP2_FIRMWARE_REVISION 0x3c
/* Flags for detected oddities and brokeness */
# define SBP2_WORKAROUND_128K_MAX_TRANS 0x1
# define SBP2_WORKAROUND_INQUIRY_36 0x2
# define SBP2_WORKAROUND_MODE_SENSE_8 0x4
# define SBP2_WORKAROUND_FIX_CAPACITY 0x8
# define SBP2_WORKAROUND_OVERRIDE 0x100
/* Management orb opcodes */
# define SBP2_LOGIN_REQUEST 0x0
# define SBP2_QUERY_LOGINS_REQUEST 0x1
# define SBP2_RECONNECT_REQUEST 0x3
# define SBP2_SET_PASSWORD_REQUEST 0x4
# define SBP2_LOGOUT_REQUEST 0x7
# define SBP2_ABORT_TASK_REQUEST 0xb
# define SBP2_ABORT_TASK_SET 0xc
# define SBP2_LOGICAL_UNIT_RESET 0xe
# define SBP2_TARGET_RESET_REQUEST 0xf
/* Offsets for command block agent registers */
# define SBP2_AGENT_STATE 0x00
# define SBP2_AGENT_RESET 0x04
# define SBP2_ORB_POINTER 0x08
# define SBP2_DOORBELL 0x10
# define SBP2_UNSOLICITED_STATUS_ENABLE 0x14
/* Status write response codes */
# define SBP2_STATUS_REQUEST_COMPLETE 0x0
# define SBP2_STATUS_TRANSPORT_FAILURE 0x1
# define SBP2_STATUS_ILLEGAL_REQUEST 0x2
# define SBP2_STATUS_VENDOR_DEPENDENT 0x3
2007-05-08 04:33:35 +04:00
# define STATUS_GET_ORB_HIGH(v) ((v).status & 0xffff)
# define STATUS_GET_SBP_STATUS(v) (((v).status >> 16) & 0xff)
# define STATUS_GET_LEN(v) (((v).status >> 24) & 0x07)
# define STATUS_GET_DEAD(v) (((v).status >> 27) & 0x01)
# define STATUS_GET_RESPONSE(v) (((v).status >> 28) & 0x03)
# define STATUS_GET_SOURCE(v) (((v).status >> 30) & 0x03)
# define STATUS_GET_ORB_LOW(v) ((v).orb_low)
# define STATUS_GET_DATA(v) ((v).data)
2006-12-20 03:58:40 +03:00
struct sbp2_status {
u32 status ;
u32 orb_low ;
u8 data [ 24 ] ;
} ;
struct sbp2_pointer {
u32 high ;
u32 low ;
} ;
struct sbp2_orb {
struct fw_transaction t ;
dma_addr_t request_bus ;
int rcode ;
struct sbp2_pointer pointer ;
2007-05-08 04:33:34 +04:00
void ( * callback ) ( struct sbp2_orb * orb , struct sbp2_status * status ) ;
2006-12-20 03:58:40 +03:00
struct list_head link ;
} ;
2007-05-08 04:33:35 +04:00
# define MANAGEMENT_ORB_LUN(v) ((v))
# define MANAGEMENT_ORB_FUNCTION(v) ((v) << 16)
# define MANAGEMENT_ORB_RECONNECT(v) ((v) << 20)
2007-06-18 01:55:41 +04:00
# define MANAGEMENT_ORB_EXCLUSIVE(v) ((v) ? 1 << 28 : 0)
2007-05-08 04:33:35 +04:00
# define MANAGEMENT_ORB_REQUEST_FORMAT(v) ((v) << 29)
# define MANAGEMENT_ORB_NOTIFY ((1) << 31)
2006-12-20 03:58:40 +03:00
2007-05-08 04:33:35 +04:00
# define MANAGEMENT_ORB_RESPONSE_LENGTH(v) ((v))
# define MANAGEMENT_ORB_PASSWORD_LENGTH(v) ((v) << 16)
2006-12-20 03:58:40 +03:00
struct sbp2_management_orb {
struct sbp2_orb base ;
struct {
struct sbp2_pointer password ;
struct sbp2_pointer response ;
u32 misc ;
u32 length ;
struct sbp2_pointer status_fifo ;
} request ;
__be32 response [ 4 ] ;
dma_addr_t response_bus ;
struct completion done ;
struct sbp2_status status ;
} ;
2007-05-08 04:33:35 +04:00
# define LOGIN_RESPONSE_GET_LOGIN_ID(v) ((v).misc & 0xffff)
# define LOGIN_RESPONSE_GET_LENGTH(v) (((v).misc >> 16) & 0xffff)
2006-12-20 03:58:40 +03:00
struct sbp2_login_response {
u32 misc ;
struct sbp2_pointer command_block_agent ;
u32 reconnect_hold ;
} ;
2007-05-08 04:33:35 +04:00
# define COMMAND_ORB_DATA_SIZE(v) ((v))
# define COMMAND_ORB_PAGE_SIZE(v) ((v) << 16)
# define COMMAND_ORB_PAGE_TABLE_PRESENT ((1) << 19)
# define COMMAND_ORB_MAX_PAYLOAD(v) ((v) << 20)
# define COMMAND_ORB_SPEED(v) ((v) << 24)
# define COMMAND_ORB_DIRECTION(v) ((v) << 27)
# define COMMAND_ORB_REQUEST_FORMAT(v) ((v) << 29)
# define COMMAND_ORB_NOTIFY ((1) << 31)
2006-12-20 03:58:40 +03:00
struct sbp2_command_orb {
struct sbp2_orb base ;
struct {
struct sbp2_pointer next ;
struct sbp2_pointer data_descriptor ;
u32 misc ;
u8 command_block [ 12 ] ;
} request ;
struct scsi_cmnd * cmd ;
scsi_done_fn_t done ;
struct fw_unit * unit ;
struct sbp2_pointer page_table [ SG_ALL ] ;
dma_addr_t page_table_bus ;
} ;
/*
* List of devices with known bugs .
*
* The firmware_revision field , masked with 0xffff00 , is the best
* indicator for the type of bridge chip of a device . It yields a few
* false positives but this did not break correctly behaving devices
* so far . We use ~ 0 as a wildcard , since the 24 bit values we get
* from the config rom can never match that .
*/
static const struct {
u32 firmware_revision ;
u32 model ;
unsigned workarounds ;
} sbp2_workarounds_table [ ] = {
/* DViCO Momobay CX-1 with TSB42AA9 bridge */ {
. firmware_revision = 0x002800 ,
. model = 0x001010 ,
. workarounds = SBP2_WORKAROUND_INQUIRY_36 |
SBP2_WORKAROUND_MODE_SENSE_8 ,
} ,
/* Initio bridges, actually only needed for some older ones */ {
. firmware_revision = 0x000200 ,
. model = ~ 0 ,
. workarounds = SBP2_WORKAROUND_INQUIRY_36 ,
} ,
/* Symbios bridge */ {
. firmware_revision = 0xa0b800 ,
. model = ~ 0 ,
. workarounds = SBP2_WORKAROUND_128K_MAX_TRANS ,
} ,
2007-05-08 04:33:32 +04:00
/*
* There are iPods ( 2 nd gen , 3 rd gen ) with model_id = = 0 , but
2006-12-20 03:58:40 +03:00
* these iPods do not feature the read_capacity bug according
* to one report . Read_capacity behaviour as well as model_id
2007-05-08 04:33:32 +04:00
* could change due to Apple - supplied firmware updates though .
*/
2006-12-20 03:58:40 +03:00
/* iPod 4th generation. */ {
. firmware_revision = 0x0a2700 ,
. model = 0x000021 ,
. workarounds = SBP2_WORKAROUND_FIX_CAPACITY ,
} ,
/* iPod mini */ {
. firmware_revision = 0x0a2700 ,
. model = 0x000023 ,
. workarounds = SBP2_WORKAROUND_FIX_CAPACITY ,
} ,
/* iPod Photo */ {
. firmware_revision = 0x0a2700 ,
. model = 0x00007e ,
. workarounds = SBP2_WORKAROUND_FIX_CAPACITY ,
}
} ;
static void
sbp2_status_write ( struct fw_card * card , struct fw_request * request ,
int tcode , int destination , int source ,
int generation , int speed ,
unsigned long long offset ,
void * payload , size_t length , void * callback_data )
{
struct sbp2_device * sd = callback_data ;
struct sbp2_orb * orb ;
struct sbp2_status status ;
size_t header_size ;
unsigned long flags ;
if ( tcode ! = TCODE_WRITE_BLOCK_REQUEST | |
2007-05-10 03:23:14 +04:00
length = = 0 | | length > sizeof ( status ) ) {
2006-12-20 03:58:40 +03:00
fw_send_response ( card , request , RCODE_TYPE_ERROR ) ;
return ;
}
header_size = min ( length , 2 * sizeof ( u32 ) ) ;
fw_memcpy_from_be32 ( & status , payload , header_size ) ;
if ( length > header_size )
memcpy ( status . data , payload + 8 , length - header_size ) ;
2007-05-08 04:33:35 +04:00
if ( STATUS_GET_SOURCE ( status ) = = 2 | | STATUS_GET_SOURCE ( status ) = = 3 ) {
2006-12-20 03:58:40 +03:00
fw_notify ( " non-orb related status write, not handled \n " ) ;
fw_send_response ( card , request , RCODE_COMPLETE ) ;
return ;
}
/* Lookup the orb corresponding to this status write. */
spin_lock_irqsave ( & card - > lock , flags ) ;
list_for_each_entry ( orb , & sd - > orb_list , link ) {
2007-05-08 04:33:35 +04:00
if ( STATUS_GET_ORB_HIGH ( status ) = = 0 & &
STATUS_GET_ORB_LOW ( status ) = = orb - > request_bus & &
2007-04-11 02:11:20 +04:00
orb - > rcode = = RCODE_COMPLETE ) {
2006-12-20 03:58:40 +03:00
list_del ( & orb - > link ) ;
break ;
}
}
spin_unlock_irqrestore ( & card - > lock , flags ) ;
if ( & orb - > link ! = & sd - > orb_list )
orb - > callback ( orb , & status ) ;
else
fw_error ( " status write for unknown orb \n " ) ;
fw_send_response ( card , request , RCODE_COMPLETE ) ;
}
static void
complete_transaction ( struct fw_card * card , int rcode ,
void * payload , size_t length , void * data )
{
struct sbp2_orb * orb = data ;
unsigned long flags ;
orb - > rcode = rcode ;
if ( rcode ! = RCODE_COMPLETE ) {
spin_lock_irqsave ( & card - > lock , flags ) ;
list_del ( & orb - > link ) ;
spin_unlock_irqrestore ( & card - > lock , flags ) ;
orb - > callback ( orb , NULL ) ;
}
}
static void
sbp2_send_orb ( struct sbp2_orb * orb , struct fw_unit * unit ,
int node_id , int generation , u64 offset )
{
struct fw_device * device = fw_device ( unit - > device . parent ) ;
struct sbp2_device * sd = unit - > device . driver_data ;
unsigned long flags ;
orb - > pointer . high = 0 ;
orb - > pointer . low = orb - > request_bus ;
2007-05-10 03:23:14 +04:00
fw_memcpy_to_be32 ( & orb - > pointer , & orb - > pointer , sizeof ( orb - > pointer ) ) ;
2006-12-20 03:58:40 +03:00
spin_lock_irqsave ( & device - > card - > lock , flags ) ;
list_add_tail ( & orb - > link , & sd - > orb_list ) ;
spin_unlock_irqrestore ( & device - > card - > lock , flags ) ;
fw_send_request ( device - > card , & orb - > t , TCODE_WRITE_BLOCK_REQUEST ,
2007-06-10 23:31:36 +04:00
node_id , generation , device - > max_speed , offset ,
2007-05-10 03:23:14 +04:00
& orb - > pointer , sizeof ( orb - > pointer ) ,
2006-12-20 03:58:40 +03:00
complete_transaction , orb ) ;
}
2007-03-07 20:12:47 +03:00
static int sbp2_cancel_orbs ( struct fw_unit * unit )
2006-12-20 03:58:40 +03:00
{
struct fw_device * device = fw_device ( unit - > device . parent ) ;
struct sbp2_device * sd = unit - > device . driver_data ;
struct sbp2_orb * orb , * next ;
struct list_head list ;
unsigned long flags ;
2007-03-07 20:12:47 +03:00
int retval = - ENOENT ;
2006-12-20 03:58:40 +03:00
INIT_LIST_HEAD ( & list ) ;
spin_lock_irqsave ( & device - > card - > lock , flags ) ;
list_splice_init ( & sd - > orb_list , & list ) ;
spin_unlock_irqrestore ( & device - > card - > lock , flags ) ;
list_for_each_entry_safe ( orb , next , & list , link ) {
2007-03-07 20:12:47 +03:00
retval = 0 ;
2007-02-06 22:49:32 +03:00
if ( fw_cancel_transaction ( device - > card , & orb - > t ) = = 0 )
continue ;
2006-12-20 03:58:40 +03:00
orb - > rcode = RCODE_CANCELLED ;
orb - > callback ( orb , NULL ) ;
}
2007-03-07 20:12:47 +03:00
return retval ;
2007-02-06 22:49:33 +03:00
}
2006-12-20 03:58:40 +03:00
static void
complete_management_orb ( struct sbp2_orb * base_orb , struct sbp2_status * status )
{
struct sbp2_management_orb * orb =
2007-06-28 00:04:33 +04:00
container_of ( base_orb , struct sbp2_management_orb , base ) ;
2006-12-20 03:58:40 +03:00
if ( status )
2007-05-10 03:23:14 +04:00
memcpy ( & orb - > status , status , sizeof ( * status ) ) ;
2006-12-20 03:58:40 +03:00
complete ( & orb - > done ) ;
}
static int
sbp2_send_management_orb ( struct fw_unit * unit , int node_id , int generation ,
int function , int lun , void * response )
{
struct fw_device * device = fw_device ( unit - > device . parent ) ;
struct sbp2_device * sd = unit - > device . driver_data ;
struct sbp2_management_orb * orb ;
int retval = - ENOMEM ;
2007-05-10 03:23:14 +04:00
orb = kzalloc ( sizeof ( * orb ) , GFP_ATOMIC ) ;
2006-12-20 03:58:40 +03:00
if ( orb = = NULL )
return - ENOMEM ;
2007-05-08 04:33:32 +04:00
/*
* The sbp2 device is going to send a block read request to
* read out the request from host memory , so map it for dma .
*/
2006-12-20 03:58:40 +03:00
orb - > base . request_bus =
dma_map_single ( device - > card - > device , & orb - > request ,
2007-05-10 03:23:14 +04:00
sizeof ( orb - > request ) , DMA_TO_DEVICE ) ;
2007-02-06 22:49:40 +03:00
if ( dma_mapping_error ( orb - > base . request_bus ) )
2006-12-20 03:58:40 +03:00
goto out ;
orb - > response_bus =
dma_map_single ( device - > card - > device , & orb - > response ,
2007-05-10 03:23:14 +04:00
sizeof ( orb - > response ) , DMA_FROM_DEVICE ) ;
2007-02-06 22:49:40 +03:00
if ( dma_mapping_error ( orb - > response_bus ) )
2006-12-20 03:58:40 +03:00
goto out ;
orb - > request . response . high = 0 ;
orb - > request . response . low = orb - > response_bus ;
orb - > request . misc =
2007-05-08 04:33:35 +04:00
MANAGEMENT_ORB_NOTIFY |
MANAGEMENT_ORB_FUNCTION ( function ) |
MANAGEMENT_ORB_LUN ( lun ) ;
2006-12-20 03:58:40 +03:00
orb - > request . length =
2007-05-10 03:23:14 +04:00
MANAGEMENT_ORB_RESPONSE_LENGTH ( sizeof ( orb - > response ) ) ;
2006-12-20 03:58:40 +03:00
orb - > request . status_fifo . high = sd - > address_handler . offset > > 32 ;
orb - > request . status_fifo . low = sd - > address_handler . offset ;
if ( function = = SBP2_LOGIN_REQUEST ) {
orb - > request . misc | =
2007-06-18 01:55:41 +04:00
MANAGEMENT_ORB_EXCLUSIVE ( sbp2_param_exclusive_login ) |
2007-05-08 04:33:35 +04:00
MANAGEMENT_ORB_RECONNECT ( 0 ) ;
2006-12-20 03:58:40 +03:00
}
2007-05-10 03:23:14 +04:00
fw_memcpy_to_be32 ( & orb - > request , & orb - > request , sizeof ( orb - > request ) ) ;
2006-12-20 03:58:40 +03:00
init_completion ( & orb - > done ) ;
orb - > base . callback = complete_management_orb ;
2007-03-07 20:12:47 +03:00
2006-12-20 03:58:40 +03:00
sbp2_send_orb ( & orb - > base , unit ,
node_id , generation , sd - > management_agent_address ) ;
2007-03-07 20:12:47 +03:00
wait_for_completion_timeout ( & orb - > done ,
msecs_to_jiffies ( SBP2_ORB_TIMEOUT ) ) ;
2006-12-20 03:58:40 +03:00
retval = - EIO ;
2007-03-07 20:12:47 +03:00
if ( sbp2_cancel_orbs ( unit ) = = 0 ) {
fw_error ( " orb reply timed out, rcode=0x%02x \n " ,
2006-12-20 03:58:40 +03:00
orb - > base . rcode ) ;
goto out ;
}
2007-03-07 20:12:47 +03:00
if ( orb - > base . rcode ! = RCODE_COMPLETE ) {
fw_error ( " management write failed, rcode 0x%02x \n " ,
2006-12-20 03:58:40 +03:00
orb - > base . rcode ) ;
goto out ;
}
2007-05-08 04:33:35 +04:00
if ( STATUS_GET_RESPONSE ( orb - > status ) ! = 0 | |
STATUS_GET_SBP_STATUS ( orb - > status ) ! = 0 ) {
2006-12-20 03:58:40 +03:00
fw_error ( " error status: %d:%d \n " ,
2007-05-08 04:33:35 +04:00
STATUS_GET_RESPONSE ( orb - > status ) ,
STATUS_GET_SBP_STATUS ( orb - > status ) ) ;
2006-12-20 03:58:40 +03:00
goto out ;
}
retval = 0 ;
out :
dma_unmap_single ( device - > card - > device , orb - > base . request_bus ,
2007-05-10 03:23:14 +04:00
sizeof ( orb - > request ) , DMA_TO_DEVICE ) ;
2006-12-20 03:58:40 +03:00
dma_unmap_single ( device - > card - > device , orb - > response_bus ,
2007-05-10 03:23:14 +04:00
sizeof ( orb - > response ) , DMA_FROM_DEVICE ) ;
2006-12-20 03:58:40 +03:00
if ( response )
fw_memcpy_from_be32 ( response ,
2007-05-10 03:23:14 +04:00
orb - > response , sizeof ( orb - > response ) ) ;
2006-12-20 03:58:40 +03:00
kfree ( orb ) ;
return retval ;
}
static void
complete_agent_reset_write ( struct fw_card * card , int rcode ,
void * payload , size_t length , void * data )
{
struct fw_transaction * t = data ;
kfree ( t ) ;
}
static int sbp2_agent_reset ( struct fw_unit * unit )
{
struct fw_device * device = fw_device ( unit - > device . parent ) ;
struct sbp2_device * sd = unit - > device . driver_data ;
struct fw_transaction * t ;
static u32 zero ;
2007-05-10 03:23:14 +04:00
t = kzalloc ( sizeof ( * t ) , GFP_ATOMIC ) ;
2006-12-20 03:58:40 +03:00
if ( t = = NULL )
return - ENOMEM ;
fw_send_request ( device - > card , t , TCODE_WRITE_QUADLET_REQUEST ,
2007-07-01 15:54:24 +04:00
sd - > node_id , sd - > generation , device - > max_speed ,
2006-12-20 03:58:40 +03:00
sd - > command_block_agent_address + SBP2_AGENT_RESET ,
2007-05-10 03:23:14 +04:00
& zero , sizeof ( zero ) , complete_agent_reset_write , t ) ;
2006-12-20 03:58:40 +03:00
return 0 ;
}
2007-02-06 22:49:34 +03:00
static void sbp2_reconnect ( struct work_struct * work ) ;
2007-05-10 03:23:07 +04:00
static struct scsi_host_template scsi_driver_template ;
2007-02-06 22:49:34 +03:00
2007-06-18 20:46:49 +04:00
static void release_sbp2_device ( struct kref * kref )
2007-03-15 00:34:58 +03:00
{
struct sbp2_device * sd = container_of ( kref , struct sbp2_device , kref ) ;
2007-05-10 03:23:07 +04:00
struct Scsi_Host * host =
container_of ( ( void * ) sd , struct Scsi_Host , hostdata [ 0 ] ) ;
2007-03-15 00:34:58 +03:00
2007-06-18 20:46:49 +04:00
scsi_remove_host ( host ) ;
2007-03-15 00:34:58 +03:00
sbp2_send_management_orb ( sd - > unit , sd - > node_id , sd - > generation ,
SBP2_LOGOUT_REQUEST , sd - > login_id , NULL ) ;
fw_core_remove_address_handler ( & sd - > address_handler ) ;
fw_notify ( " removed sbp2 unit %s \n " , sd - > unit - > device . bus_id ) ;
put_device ( & sd - > unit - > device ) ;
2007-05-10 03:23:07 +04:00
scsi_host_put ( host ) ;
2007-03-15 00:34:58 +03:00
}
2007-02-06 22:49:34 +03:00
static void sbp2_login ( struct work_struct * work )
{
struct sbp2_device * sd =
container_of ( work , struct sbp2_device , work . work ) ;
2007-05-10 03:23:07 +04:00
struct Scsi_Host * host =
container_of ( ( void * ) sd , struct Scsi_Host , hostdata [ 0 ] ) ;
2007-02-06 22:49:34 +03:00
struct fw_unit * unit = sd - > unit ;
struct fw_device * device = fw_device ( unit - > device . parent ) ;
struct sbp2_login_response response ;
int generation , node_id , local_node_id , lun , retval ;
/* FIXME: Make this work for multi-lun devices. */
lun = 0 ;
generation = device - > card - > generation ;
node_id = device - > node - > node_id ;
local_node_id = device - > card - > local_node - > node_id ;
if ( sbp2_send_management_orb ( unit , node_id , generation ,
SBP2_LOGIN_REQUEST , lun , & response ) < 0 ) {
if ( sd - > retries + + < 5 ) {
schedule_delayed_work ( & sd - > work , DIV_ROUND_UP ( HZ , 5 ) ) ;
} else {
fw_error ( " failed to login to %s \n " ,
unit - > device . bus_id ) ;
2007-03-15 00:34:58 +03:00
kref_put ( & sd - > kref , release_sbp2_device ) ;
2007-02-06 22:49:34 +03:00
}
return ;
}
sd - > generation = generation ;
sd - > node_id = node_id ;
sd - > address_high = local_node_id < < 16 ;
/* Get command block agent offset and login id. */
sd - > command_block_agent_address =
2007-03-07 20:12:45 +03:00
( ( u64 ) ( response . command_block_agent . high & 0xffff ) < < 32 ) |
2007-02-06 22:49:34 +03:00
response . command_block_agent . low ;
2007-05-08 04:33:35 +04:00
sd - > login_id = LOGIN_RESPONSE_GET_LOGIN_ID ( response ) ;
2007-02-06 22:49:34 +03:00
2007-03-07 20:12:45 +03:00
fw_notify ( " logged in to sbp2 unit %s (%d retries) \n " ,
unit - > device . bus_id , sd - > retries ) ;
fw_notify ( " - management_agent_address: 0x%012llx \n " ,
2007-02-06 22:49:34 +03:00
( unsigned long long ) sd - > management_agent_address ) ;
fw_notify ( " - command_block_agent_address: 0x%012llx \n " ,
( unsigned long long ) sd - > command_block_agent_address ) ;
2007-03-07 20:12:45 +03:00
fw_notify ( " - status write address: 0x%012llx \n " ,
2007-02-06 22:49:34 +03:00
( unsigned long long ) sd - > address_handler . offset ) ;
#if 0
/* FIXME: The linux1394 sbp2 does this last step. */
sbp2_set_busy_timeout ( scsi_id ) ;
# endif
2007-03-07 20:12:40 +03:00
PREPARE_DELAYED_WORK ( & sd - > work , sbp2_reconnect ) ;
2007-02-06 22:49:34 +03:00
sbp2_agent_reset ( unit ) ;
2007-05-10 03:23:07 +04:00
/* FIXME: Loop over luns here. */
lun = 0 ;
retval = scsi_add_device ( host , 0 , 0 , lun ) ;
2007-02-06 22:49:34 +03:00
if ( retval < 0 ) {
sbp2_send_management_orb ( unit , sd - > node_id , sd - > generation ,
SBP2_LOGOUT_REQUEST , sd - > login_id ,
NULL ) ;
2007-05-08 04:33:32 +04:00
/*
* Set this back to sbp2_login so we fall back and
* retry login on bus reset .
*/
2007-03-07 20:12:40 +03:00
PREPARE_DELAYED_WORK ( & sd - > work , sbp2_login ) ;
2007-02-06 22:49:34 +03:00
}
2007-03-15 00:34:58 +03:00
kref_put ( & sd - > kref , release_sbp2_device ) ;
2007-02-06 22:49:34 +03:00
}
2006-12-20 03:58:40 +03:00
static int sbp2_probe ( struct device * dev )
{
struct fw_unit * unit = fw_unit ( dev ) ;
struct fw_device * device = fw_device ( unit - > device . parent ) ;
struct sbp2_device * sd ;
struct fw_csr_iterator ci ;
2007-05-10 03:23:07 +04:00
struct Scsi_Host * host ;
int i , key , value , err ;
2006-12-20 03:58:40 +03:00
u32 model , firmware_revision ;
2007-05-10 03:23:07 +04:00
err = - ENOMEM ;
host = scsi_host_alloc ( & scsi_driver_template , sizeof ( * sd ) ) ;
if ( host = = NULL )
goto fail ;
2006-12-20 03:58:40 +03:00
2007-05-10 03:23:07 +04:00
sd = ( struct sbp2_device * ) host - > hostdata ;
2006-12-20 03:58:40 +03:00
unit - > device . driver_data = sd ;
sd - > unit = unit ;
INIT_LIST_HEAD ( & sd - > orb_list ) ;
2007-03-15 00:34:58 +03:00
kref_init ( & sd - > kref ) ;
2006-12-20 03:58:40 +03:00
sd - > address_handler . length = 0x100 ;
sd - > address_handler . address_callback = sbp2_status_write ;
sd - > address_handler . callback_data = sd ;
2007-05-10 03:23:07 +04:00
err = fw_core_add_address_handler ( & sd - > address_handler ,
& fw_high_memory_region ) ;
if ( err < 0 )
goto fail_host ;
2006-12-20 03:58:40 +03:00
2007-05-10 03:23:07 +04:00
err = fw_device_enable_phys_dma ( device ) ;
if ( err < 0 )
goto fail_address_handler ;
err = scsi_add_host ( host , & unit - > device ) ;
if ( err < 0 )
goto fail_address_handler ;
2006-12-20 03:58:40 +03:00
2007-05-08 04:33:32 +04:00
/*
* Scan unit directory to get management agent address ,
2006-12-20 03:58:40 +03:00
* firmware revison and model . Initialize firmware_revision
2007-05-08 04:33:32 +04:00
* and model to values that wont match anything in our table .
*/
2006-12-20 03:58:40 +03:00
firmware_revision = 0xff000000 ;
model = 0xff000000 ;
fw_csr_iterator_init ( & ci , unit - > directory ) ;
while ( fw_csr_iterator_next ( & ci , & key , & value ) ) {
switch ( key ) {
case CSR_DEPENDENT_INFO | CSR_OFFSET :
sd - > management_agent_address =
0xfffff0000000ULL + 4 * value ;
break ;
case SBP2_FIRMWARE_REVISION :
firmware_revision = value ;
break ;
case CSR_MODEL :
model = value ;
break ;
}
}
for ( i = 0 ; i < ARRAY_SIZE ( sbp2_workarounds_table ) ; i + + ) {
if ( sbp2_workarounds_table [ i ] . firmware_revision ! =
( firmware_revision & 0xffffff00 ) )
continue ;
if ( sbp2_workarounds_table [ i ] . model ! = model & &
sbp2_workarounds_table [ i ] . model ! = ~ 0 )
continue ;
sd - > workarounds | = sbp2_workarounds_table [ i ] . workarounds ;
break ;
}
if ( sd - > workarounds )
fw_notify ( " Workarounds for node %s: 0x%x "
" (firmware_revision 0x%06x, model_id 0x%06x) \n " ,
unit - > device . bus_id ,
sd - > workarounds , firmware_revision , model ) ;
2007-03-15 00:34:58 +03:00
get_device ( & unit - > device ) ;
2007-05-08 04:33:32 +04:00
/*
* We schedule work to do the login so we can easily
2007-03-15 00:34:58 +03:00
* reschedule retries . Always get the ref before scheduling
2007-05-08 04:33:32 +04:00
* work .
*/
2007-02-06 22:49:34 +03:00
INIT_DELAYED_WORK ( & sd - > work , sbp2_login ) ;
2007-03-15 00:34:58 +03:00
if ( schedule_delayed_work ( & sd - > work , 0 ) )
kref_get ( & sd - > kref ) ;
2006-12-20 03:58:40 +03:00
return 0 ;
2007-05-10 03:23:07 +04:00
fail_address_handler :
fw_core_remove_address_handler ( & sd - > address_handler ) ;
fail_host :
scsi_host_put ( host ) ;
fail :
return err ;
2006-12-20 03:58:40 +03:00
}
static int sbp2_remove ( struct device * dev )
{
struct fw_unit * unit = fw_unit ( dev ) ;
struct sbp2_device * sd = unit - > device . driver_data ;
2007-03-15 00:34:58 +03:00
kref_put ( & sd - > kref , release_sbp2_device ) ;
2006-12-20 03:58:40 +03:00
return 0 ;
}
static void sbp2_reconnect ( struct work_struct * work )
{
2007-02-06 22:49:34 +03:00
struct sbp2_device * sd =
container_of ( work , struct sbp2_device , work . work ) ;
2006-12-20 03:58:40 +03:00
struct fw_unit * unit = sd - > unit ;
struct fw_device * device = fw_device ( unit - > device . parent ) ;
int generation , node_id , local_node_id ;
generation = device - > card - > generation ;
node_id = device - > node - > node_id ;
local_node_id = device - > card - > local_node - > node_id ;
2007-02-06 22:49:34 +03:00
if ( sbp2_send_management_orb ( unit , node_id , generation ,
SBP2_RECONNECT_REQUEST ,
sd - > login_id , NULL ) < 0 ) {
2007-03-07 20:12:45 +03:00
if ( sd - > retries + + > = 5 ) {
2007-02-06 22:49:34 +03:00
fw_error ( " failed to reconnect to %s \n " ,
unit - > device . bus_id ) ;
/* Fall back and try to log in again. */
sd - > retries = 0 ;
2007-03-07 20:12:40 +03:00
PREPARE_DELAYED_WORK ( & sd - > work , sbp2_login ) ;
2007-02-06 22:49:34 +03:00
}
schedule_delayed_work ( & sd - > work , DIV_ROUND_UP ( HZ , 5 ) ) ;
return ;
}
2006-12-20 03:58:40 +03:00
sd - > generation = generation ;
sd - > node_id = node_id ;
2007-01-23 23:11:43 +03:00
sd - > address_high = local_node_id < < 16 ;
2007-02-06 22:49:34 +03:00
2007-03-07 20:12:45 +03:00
fw_notify ( " reconnected to unit %s (%d retries) \n " ,
unit - > device . bus_id , sd - > retries ) ;
2007-02-06 22:49:34 +03:00
sbp2_agent_reset ( unit ) ;
sbp2_cancel_orbs ( unit ) ;
2007-03-15 00:34:58 +03:00
kref_put ( & sd - > kref , release_sbp2_device ) ;
2006-12-20 03:58:40 +03:00
}
static void sbp2_update ( struct fw_unit * unit )
{
struct fw_device * device = fw_device ( unit - > device . parent ) ;
struct sbp2_device * sd = unit - > device . driver_data ;
2007-02-06 22:49:34 +03:00
sd - > retries = 0 ;
2006-12-20 03:58:40 +03:00
fw_device_enable_phys_dma ( device ) ;
2007-03-15 00:34:58 +03:00
if ( schedule_delayed_work ( & sd - > work , 0 ) )
kref_get ( & sd - > kref ) ;
2006-12-20 03:58:40 +03:00
}
# define SBP2_UNIT_SPEC_ID_ENTRY 0x0000609e
# define SBP2_SW_VERSION_ENTRY 0x00010483
2007-01-14 17:29:07 +03:00
static const struct fw_device_id sbp2_id_table [ ] = {
2006-12-20 03:58:40 +03:00
{
. match_flags = FW_MATCH_SPECIFIER_ID | FW_MATCH_VERSION ,
. specifier_id = SBP2_UNIT_SPEC_ID_ENTRY ,
2007-01-21 22:45:32 +03:00
. version = SBP2_SW_VERSION_ENTRY ,
2006-12-20 03:58:40 +03:00
} ,
{ }
} ;
static struct fw_driver sbp2_driver = {
. driver = {
. owner = THIS_MODULE ,
. name = sbp2_driver_name ,
. bus = & fw_bus_type ,
. probe = sbp2_probe ,
. remove = sbp2_remove ,
} ,
. update = sbp2_update ,
. id_table = sbp2_id_table ,
} ;
2007-04-11 02:11:18 +04:00
static unsigned int
sbp2_status_to_sense_data ( u8 * sbp2_status , u8 * sense_data )
2006-12-20 03:58:40 +03:00
{
2007-04-11 02:11:18 +04:00
int sam_status ;
2006-12-20 03:58:40 +03:00
sense_data [ 0 ] = 0x70 ;
sense_data [ 1 ] = 0x0 ;
sense_data [ 2 ] = sbp2_status [ 1 ] ;
sense_data [ 3 ] = sbp2_status [ 4 ] ;
sense_data [ 4 ] = sbp2_status [ 5 ] ;
sense_data [ 5 ] = sbp2_status [ 6 ] ;
sense_data [ 6 ] = sbp2_status [ 7 ] ;
sense_data [ 7 ] = 10 ;
sense_data [ 8 ] = sbp2_status [ 8 ] ;
sense_data [ 9 ] = sbp2_status [ 9 ] ;
sense_data [ 10 ] = sbp2_status [ 10 ] ;
sense_data [ 11 ] = sbp2_status [ 11 ] ;
sense_data [ 12 ] = sbp2_status [ 2 ] ;
sense_data [ 13 ] = sbp2_status [ 3 ] ;
sense_data [ 14 ] = sbp2_status [ 12 ] ;
sense_data [ 15 ] = sbp2_status [ 13 ] ;
2007-04-11 02:11:18 +04:00
sam_status = sbp2_status [ 0 ] & 0x3f ;
2006-12-20 03:58:40 +03:00
2007-04-11 02:11:18 +04:00
switch ( sam_status ) {
case SAM_STAT_GOOD :
2006-12-20 03:58:40 +03:00
case SAM_STAT_CHECK_CONDITION :
case SAM_STAT_CONDITION_MET :
2007-04-11 02:11:18 +04:00
case SAM_STAT_BUSY :
2006-12-20 03:58:40 +03:00
case SAM_STAT_RESERVATION_CONFLICT :
case SAM_STAT_COMMAND_TERMINATED :
2007-04-11 02:11:18 +04:00
return DID_OK < < 16 | sam_status ;
2006-12-20 03:58:40 +03:00
default :
2007-04-11 02:11:18 +04:00
return DID_ERROR < < 16 ;
2006-12-20 03:58:40 +03:00
}
}
static void
complete_command_orb ( struct sbp2_orb * base_orb , struct sbp2_status * status )
{
2007-06-28 00:04:33 +04:00
struct sbp2_command_orb * orb =
container_of ( base_orb , struct sbp2_command_orb , base ) ;
2006-12-20 03:58:40 +03:00
struct fw_unit * unit = orb - > unit ;
struct fw_device * device = fw_device ( unit - > device . parent ) ;
struct scatterlist * sg ;
int result ;
if ( status ! = NULL ) {
2007-05-08 04:33:35 +04:00
if ( STATUS_GET_DEAD ( * status ) )
2006-12-20 03:58:40 +03:00
sbp2_agent_reset ( unit ) ;
2007-05-08 04:33:35 +04:00
switch ( STATUS_GET_RESPONSE ( * status ) ) {
2006-12-20 03:58:40 +03:00
case SBP2_STATUS_REQUEST_COMPLETE :
2007-04-11 02:11:18 +04:00
result = DID_OK < < 16 ;
2006-12-20 03:58:40 +03:00
break ;
case SBP2_STATUS_TRANSPORT_FAILURE :
2007-04-11 02:11:18 +04:00
result = DID_BUS_BUSY < < 16 ;
2006-12-20 03:58:40 +03:00
break ;
case SBP2_STATUS_ILLEGAL_REQUEST :
case SBP2_STATUS_VENDOR_DEPENDENT :
default :
2007-04-11 02:11:18 +04:00
result = DID_ERROR < < 16 ;
2006-12-20 03:58:40 +03:00
break ;
}
2007-05-08 04:33:35 +04:00
if ( result = = DID_OK < < 16 & & STATUS_GET_LEN ( * status ) > 1 )
result = sbp2_status_to_sense_data ( STATUS_GET_DATA ( * status ) ,
2006-12-20 03:58:40 +03:00
orb - > cmd - > sense_buffer ) ;
} else {
2007-05-08 04:33:32 +04:00
/*
* If the orb completes with status = = NULL , something
2006-12-20 03:58:40 +03:00
* went wrong , typically a bus reset happened mid - orb
2007-05-08 04:33:32 +04:00
* or when sending the write ( less likely ) .
*/
2007-04-11 02:11:18 +04:00
result = DID_BUS_BUSY < < 16 ;
2006-12-20 03:58:40 +03:00
}
dma_unmap_single ( device - > card - > device , orb - > base . request_bus ,
2007-05-10 03:23:14 +04:00
sizeof ( orb - > request ) , DMA_TO_DEVICE ) ;
2006-12-20 03:58:40 +03:00
if ( orb - > cmd - > use_sg > 0 ) {
sg = ( struct scatterlist * ) orb - > cmd - > request_buffer ;
dma_unmap_sg ( device - > card - > device , sg , orb - > cmd - > use_sg ,
orb - > cmd - > sc_data_direction ) ;
}
if ( orb - > page_table_bus ! = 0 )
dma_unmap_single ( device - > card - > device , orb - > page_table_bus ,
2007-05-10 03:23:14 +04:00
sizeof ( orb - > page_table_bus ) , DMA_TO_DEVICE ) ;
2006-12-20 03:58:40 +03:00
2007-04-11 02:11:18 +04:00
orb - > cmd - > result = result ;
2006-12-20 03:58:40 +03:00
orb - > done ( orb - > cmd ) ;
kfree ( orb ) ;
}
2007-05-10 03:23:08 +04:00
static int sbp2_command_orb_map_scatterlist ( struct sbp2_command_orb * orb )
2006-12-20 03:58:40 +03:00
{
2007-05-10 03:23:07 +04:00
struct sbp2_device * sd =
( struct sbp2_device * ) orb - > cmd - > device - > host - > hostdata ;
struct fw_unit * unit = sd - > unit ;
2006-12-20 03:58:40 +03:00
struct fw_device * device = fw_device ( unit - > device . parent ) ;
struct scatterlist * sg ;
int sg_len , l , i , j , count ;
size_t size ;
dma_addr_t sg_addr ;
sg = ( struct scatterlist * ) orb - > cmd - > request_buffer ;
count = dma_map_sg ( device - > card - > device , sg , orb - > cmd - > use_sg ,
orb - > cmd - > sc_data_direction ) ;
2007-05-10 03:23:08 +04:00
if ( count = = 0 )
goto fail ;
2006-12-20 03:58:40 +03:00
2007-05-08 04:33:32 +04:00
/*
* Handle the special case where there is only one element in
2006-12-20 03:58:40 +03:00
* the scatter list by converting it to an immediate block
* request . This is also a workaround for broken devices such
* as the second generation iPod which doesn ' t support page
2007-05-08 04:33:32 +04:00
* tables .
*/
2006-12-20 03:58:40 +03:00
if ( count = = 1 & & sg_dma_len ( sg ) < SBP2_MAX_SG_ELEMENT_LENGTH ) {
orb - > request . data_descriptor . high = sd - > address_high ;
orb - > request . data_descriptor . low = sg_dma_address ( sg ) ;
orb - > request . misc | =
2007-05-08 04:33:35 +04:00
COMMAND_ORB_DATA_SIZE ( sg_dma_len ( sg ) ) ;
2007-05-10 03:23:08 +04:00
return 0 ;
2006-12-20 03:58:40 +03:00
}
2007-05-08 04:33:32 +04:00
/*
* Convert the scatterlist to an sbp2 page table . If any
2007-05-10 03:23:10 +04:00
* scatterlist entries are too big for sbp2 , we split them as we
* go . Even if we ask the block I / O layer to not give us sg
* elements larger than 65535 bytes , some IOMMUs may merge sg elements
* during DMA mapping , and Linux currently doesn ' t prevent this .
2007-05-08 04:33:32 +04:00
*/
2006-12-20 03:58:40 +03:00
for ( i = 0 , j = 0 ; i < count ; i + + ) {
sg_len = sg_dma_len ( sg + i ) ;
sg_addr = sg_dma_address ( sg + i ) ;
while ( sg_len ) {
l = min ( sg_len , SBP2_MAX_SG_ELEMENT_LENGTH ) ;
orb - > page_table [ j ] . low = sg_addr ;
orb - > page_table [ j ] . high = ( l < < 16 ) ;
sg_addr + = l ;
sg_len - = l ;
j + + ;
}
}
2007-05-10 03:23:14 +04:00
size = sizeof ( orb - > page_table [ 0 ] ) * j ;
2006-12-20 03:58:40 +03:00
2007-05-08 04:33:32 +04:00
/*
* The data_descriptor pointer is the one case where we need
2006-12-20 03:58:40 +03:00
* to fill in the node ID part of the address . All other
* pointers assume that the data referenced reside on the
* initiator ( i . e . us ) , but data_descriptor can refer to data
2007-05-08 04:33:32 +04:00
* on other nodes so we need to put our ID in descriptor . high .
*/
2006-12-20 03:58:40 +03:00
orb - > page_table_bus =
dma_map_single ( device - > card - > device , orb - > page_table ,
size , DMA_TO_DEVICE ) ;
2007-05-10 03:23:08 +04:00
if ( dma_mapping_error ( orb - > page_table_bus ) )
goto fail_page_table ;
2006-12-20 03:58:40 +03:00
orb - > request . data_descriptor . high = sd - > address_high ;
orb - > request . data_descriptor . low = orb - > page_table_bus ;
orb - > request . misc | =
2007-05-08 04:33:35 +04:00
COMMAND_ORB_PAGE_TABLE_PRESENT |
COMMAND_ORB_DATA_SIZE ( j ) ;
2006-12-20 03:58:40 +03:00
fw_memcpy_to_be32 ( orb - > page_table , orb - > page_table , size ) ;
2007-05-10 03:23:08 +04:00
return 0 ;
fail_page_table :
dma_unmap_sg ( device - > card - > device , sg , orb - > cmd - > use_sg ,
orb - > cmd - > sc_data_direction ) ;
fail :
return - ENOMEM ;
2006-12-20 03:58:40 +03:00
}
/* SCSI stack integration */
static int sbp2_scsi_queuecommand ( struct scsi_cmnd * cmd , scsi_done_fn_t done )
{
2007-05-10 03:23:07 +04:00
struct sbp2_device * sd =
( struct sbp2_device * ) cmd - > device - > host - > hostdata ;
struct fw_unit * unit = sd - > unit ;
2006-12-20 03:58:40 +03:00
struct fw_device * device = fw_device ( unit - > device . parent ) ;
struct sbp2_command_orb * orb ;
2007-05-08 04:33:32 +04:00
/*
* Bidirectional commands are not yet implemented , and unknown
* transfer direction not handled .
*/
2006-12-20 03:58:40 +03:00
if ( cmd - > sc_data_direction = = DMA_BIDIRECTIONAL ) {
2007-06-09 21:26:22 +04:00
fw_error ( " Can't handle DMA_BIDIRECTIONAL, rejecting command \n " ) ;
2007-05-10 03:23:09 +04:00
cmd - > result = DID_ERROR < < 16 ;
done ( cmd ) ;
return 0 ;
2006-12-20 03:58:40 +03:00
}
2007-05-10 03:23:14 +04:00
orb = kzalloc ( sizeof ( * orb ) , GFP_ATOMIC ) ;
2006-12-20 03:58:40 +03:00
if ( orb = = NULL ) {
fw_notify ( " failed to alloc orb \n " ) ;
2007-02-06 22:49:40 +03:00
goto fail_alloc ;
2006-12-20 03:58:40 +03:00
}
2007-04-11 02:11:20 +04:00
/* Initialize rcode to something not RCODE_COMPLETE. */
orb - > base . rcode = - 1 ;
2006-12-20 03:58:40 +03:00
orb - > base . request_bus =
dma_map_single ( device - > card - > device , & orb - > request ,
2007-05-10 03:23:14 +04:00
sizeof ( orb - > request ) , DMA_TO_DEVICE ) ;
2007-02-06 22:49:40 +03:00
if ( dma_mapping_error ( orb - > base . request_bus ) )
goto fail_mapping ;
2006-12-20 03:58:40 +03:00
orb - > unit = unit ;
orb - > done = done ;
orb - > cmd = cmd ;
orb - > request . next . high = SBP2_ORB_NULL ;
orb - > request . next . low = 0x0 ;
2007-05-08 04:33:32 +04:00
/*
* At speed 100 we can do 512 bytes per packet , at speed 200 ,
2006-12-20 03:58:40 +03:00
* 1024 bytes per packet etc . The SBP - 2 max_payload field
* specifies the max payload size as 2 ^ ( max_payload + 2 ) , so
2007-05-08 04:33:32 +04:00
* if we set this to max_speed + 7 , we get the right value .
*/
2006-12-20 03:58:40 +03:00
orb - > request . misc =
2007-06-10 23:31:36 +04:00
COMMAND_ORB_MAX_PAYLOAD ( device - > max_speed + 7 ) |
COMMAND_ORB_SPEED ( device - > max_speed ) |
2007-05-08 04:33:35 +04:00
COMMAND_ORB_NOTIFY ;
2006-12-20 03:58:40 +03:00
if ( cmd - > sc_data_direction = = DMA_FROM_DEVICE )
orb - > request . misc | =
2007-05-08 04:33:35 +04:00
COMMAND_ORB_DIRECTION ( SBP2_DIRECTION_FROM_MEDIA ) ;
2006-12-20 03:58:40 +03:00
else if ( cmd - > sc_data_direction = = DMA_TO_DEVICE )
orb - > request . misc | =
2007-05-08 04:33:35 +04:00
COMMAND_ORB_DIRECTION ( SBP2_DIRECTION_TO_MEDIA ) ;
2006-12-20 03:58:40 +03:00
2007-05-10 03:23:11 +04:00
if ( cmd - > use_sg & & sbp2_command_orb_map_scatterlist ( orb ) < 0 )
2007-05-10 03:23:08 +04:00
goto fail_map_payload ;
2006-12-20 03:58:40 +03:00
2007-05-10 03:23:14 +04:00
fw_memcpy_to_be32 ( & orb - > request , & orb - > request , sizeof ( orb - > request ) ) ;
2006-12-20 03:58:40 +03:00
memset ( orb - > request . command_block ,
2007-05-10 03:23:14 +04:00
0 , sizeof ( orb - > request . command_block ) ) ;
2006-12-20 03:58:40 +03:00
memcpy ( orb - > request . command_block , cmd - > cmnd , COMMAND_SIZE ( * cmd - > cmnd ) ) ;
orb - > base . callback = complete_command_orb ;
sbp2_send_orb ( & orb - > base , unit , sd - > node_id , sd - > generation ,
sd - > command_block_agent_address + SBP2_ORB_POINTER ) ;
return 0 ;
2007-02-06 22:49:40 +03:00
2007-05-10 03:23:08 +04:00
fail_map_payload :
2007-02-06 22:49:40 +03:00
dma_unmap_single ( device - > card - > device , orb - > base . request_bus ,
2007-05-10 03:23:14 +04:00
sizeof ( orb - > request ) , DMA_TO_DEVICE ) ;
2007-02-06 22:49:40 +03:00
fail_mapping :
kfree ( orb ) ;
fail_alloc :
2007-05-10 03:23:09 +04:00
return SCSI_MLQUEUE_HOST_BUSY ;
2006-12-20 03:58:40 +03:00
}
2007-01-23 23:20:08 +03:00
static int sbp2_scsi_slave_alloc ( struct scsi_device * sdev )
{
2007-05-10 03:23:07 +04:00
struct sbp2_device * sd = ( struct sbp2_device * ) sdev - > host - > hostdata ;
2007-01-23 23:20:08 +03:00
sdev - > allow_restart = 1 ;
if ( sd - > workarounds & SBP2_WORKAROUND_INQUIRY_36 )
sdev - > inquiry_len = 36 ;
return 0 ;
}
2006-12-20 03:58:40 +03:00
static int sbp2_scsi_slave_configure ( struct scsi_device * sdev )
{
2007-05-10 03:23:07 +04:00
struct sbp2_device * sd = ( struct sbp2_device * ) sdev - > host - > hostdata ;
struct fw_unit * unit = sd - > unit ;
2006-12-20 03:58:40 +03:00
2007-01-23 23:20:08 +03:00
sdev - > use_10_for_rw = 1 ;
if ( sdev - > type = = TYPE_ROM )
sdev - > use_10_for_ms = 1 ;
2006-12-20 03:58:40 +03:00
if ( sdev - > type = = TYPE_DISK & &
sd - > workarounds & SBP2_WORKAROUND_MODE_SENSE_8 )
sdev - > skip_ms_page_8 = 1 ;
if ( sd - > workarounds & SBP2_WORKAROUND_FIX_CAPACITY ) {
fw_notify ( " setting fix_capacity for %s \n " , unit - > device . bus_id ) ;
sdev - > fix_capacity = 1 ;
}
2007-06-18 01:52:08 +04:00
if ( sd - > workarounds & SBP2_WORKAROUND_128K_MAX_TRANS )
blk_queue_max_sectors ( sdev - > request_queue , 128 * 1024 / 512 ) ;
2006-12-20 03:58:40 +03:00
return 0 ;
}
/*
* Called by scsi stack when something has really gone wrong . Usually
* called when a command has timed - out for some reason .
*/
static int sbp2_scsi_abort ( struct scsi_cmnd * cmd )
{
2007-05-10 03:23:07 +04:00
struct sbp2_device * sd =
( struct sbp2_device * ) cmd - > device - > host - > hostdata ;
struct fw_unit * unit = sd - > unit ;
2006-12-20 03:58:40 +03:00
fw_notify ( " sbp2_scsi_abort \n " ) ;
2007-04-12 02:44:33 +04:00
sbp2_agent_reset ( unit ) ;
2006-12-20 03:58:40 +03:00
sbp2_cancel_orbs ( unit ) ;
return SUCCESS ;
}
2007-05-27 15:18:27 +04:00
/*
* Format of / sys / bus / scsi / devices / . . . / ieee1394_id :
* u64 EUI - 64 : u24 directory_ID : u16 LUN ( all printed in hexadecimal )
*
* This is the concatenation of target port identifier and logical unit
* identifier as per SAM - 2. . . SAM - 4 annex A .
*/
static ssize_t
sbp2_sysfs_ieee1394_id_show ( struct device * dev , struct device_attribute * attr ,
char * buf )
{
struct scsi_device * sdev = to_scsi_device ( dev ) ;
struct sbp2_device * sd ;
struct fw_unit * unit ;
struct fw_device * device ;
u32 directory_id ;
struct fw_csr_iterator ci ;
int key , value , lun ;
if ( ! sdev )
return 0 ;
sd = ( struct sbp2_device * ) sdev - > host - > hostdata ;
unit = sd - > unit ;
device = fw_device ( unit - > device . parent ) ;
/* implicit directory ID */
directory_id = ( ( unit - > directory - device - > config_rom ) * 4
+ CSR_CONFIG_ROM ) & 0xffffff ;
/* explicit directory ID, overrides implicit ID if present */
fw_csr_iterator_init ( & ci , unit - > directory ) ;
while ( fw_csr_iterator_next ( & ci , & key , & value ) )
if ( key = = CSR_DIRECTORY_ID ) {
directory_id = value ;
break ;
}
/* FIXME: Make this work for multi-lun devices. */
lun = 0 ;
return sprintf ( buf , " %08x%08x:%06x:%04x \n " ,
device - > config_rom [ 3 ] , device - > config_rom [ 4 ] ,
directory_id , lun ) ;
}
static DEVICE_ATTR ( ieee1394_id , S_IRUGO , sbp2_sysfs_ieee1394_id_show , NULL ) ;
static struct device_attribute * sbp2_scsi_sysfs_attrs [ ] = {
& dev_attr_ieee1394_id ,
NULL
} ;
2006-12-20 03:58:40 +03:00
static struct scsi_host_template scsi_driver_template = {
. module = THIS_MODULE ,
. name = " SBP-2 IEEE-1394 " ,
. proc_name = ( char * ) sbp2_driver_name ,
. queuecommand = sbp2_scsi_queuecommand ,
2007-01-23 23:20:08 +03:00
. slave_alloc = sbp2_scsi_slave_alloc ,
2006-12-20 03:58:40 +03:00
. slave_configure = sbp2_scsi_slave_configure ,
. eh_abort_handler = sbp2_scsi_abort ,
. this_id = - 1 ,
. sg_tablesize = SG_ALL ,
. use_clustering = ENABLE_CLUSTERING ,
2007-01-21 22:50:11 +03:00
. cmd_per_lun = 1 ,
. can_queue = 1 ,
2007-05-27 15:18:27 +04:00
. sdev_attrs = sbp2_scsi_sysfs_attrs ,
2006-12-20 03:58:40 +03:00
} ;
MODULE_AUTHOR ( " Kristian Hoegsberg <krh@bitplanet.net> " ) ;
MODULE_DESCRIPTION ( " SCSI over IEEE1394 " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DEVICE_TABLE ( ieee1394 , sbp2_id_table ) ;
2007-05-06 01:17:13 +04:00
/* Provide a module alias so root-on-sbp2 initrds don't break. */
# ifndef CONFIG_IEEE1394_SBP2_MODULE
MODULE_ALIAS ( " sbp2 " ) ;
# endif
2006-12-20 03:58:40 +03:00
static int __init sbp2_init ( void )
{
return driver_register ( & sbp2_driver . driver ) ;
}
static void __exit sbp2_cleanup ( void )
{
driver_unregister ( & sbp2_driver . driver ) ;
}
module_init ( sbp2_init ) ;
module_exit ( sbp2_cleanup ) ;