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 .
*/
2008-02-04 01:12:17 +03:00
# include <linux/blkdev.h>
# include <linux/delay.h>
# include <linux/device.h>
# include <linux/dma-mapping.h>
2006-12-20 03:58:40 +03:00
# include <linux/kernel.h>
2008-02-04 01:12:17 +03:00
# include <linux/mod_devicetable.h>
2006-12-20 03:58:40 +03:00
# include <linux/module.h>
2007-06-18 01:55:41 +04:00
# include <linux/moduleparam.h>
2006-12-28 01:49:23 +03:00
# include <linux/scatterlist.h>
2007-07-01 15:54:57 +04:00
# include <linux/string.h>
2007-08-13 19:48:25 +04:00
# include <linux/stringify.h>
2007-02-06 22:49:33 +03:00
# include <linux/timer.h>
2007-08-12 14:51:18 +04:00
# include <linux/workqueue.h>
2008-01-25 20:57:41 +03:00
# include <asm/system.h>
2006-12-20 03:58:40 +03:00
# include <scsi/scsi.h>
# include <scsi/scsi_cmnd.h>
# include <scsi/scsi_device.h>
# include <scsi/scsi_host.h>
# include "fw-device.h"
2008-02-04 01:12:17 +03:00
# include "fw-topology.h"
# include "fw-transaction.h"
2006-12-20 03:58:40 +03:00
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) " ) ;
2007-08-13 19:48:25 +04:00
/*
* Flags for firmware oddities
*
* - 128 kB max transfer
* Limit transfer size . Necessary for some old bridges .
*
* - 36 byte inquiry
* When scsi_mod probes the device , let the inquiry command look like that
* from MS Windows .
*
* - skip mode page 8
* Suppress sending of mode_sense for mode page 8 if the device pretends to
* support the SCSI Primary Block commands instead of Reduced Block Commands .
*
* - fix capacity
* Tell sd_mod to correct the last sector number reported by read_capacity .
* Avoids access beyond actual disk limits on devices with an off - by - one bug .
* Don ' t use this with devices which don ' t have this bug .
*
2008-02-04 01:04:38 +03:00
* - delay inquiry
* Wait extra SBP2_INQUIRY_DELAY seconds after login before SCSI inquiry .
*
2007-08-13 19:48:25 +04:00
* - override internal blacklist
* Instead of adding to the built - in blacklist , use only the workarounds
* specified in the module load parameter .
* Useful if a blacklist entry interfered with a non - broken device .
*/
# 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
2008-02-04 01:04:38 +03:00
# define SBP2_WORKAROUND_DELAY_INQUIRY 0x10
# define SBP2_INQUIRY_DELAY 12
2007-08-13 19:48:25 +04:00
# define SBP2_WORKAROUND_OVERRIDE 0x100
static int sbp2_param_workarounds ;
module_param_named ( workarounds , sbp2_param_workarounds , int , 0644 ) ;
MODULE_PARM_DESC ( workarounds , " Work around device bugs (default = 0 "
" , 128kB max transfer = " __stringify ( SBP2_WORKAROUND_128K_MAX_TRANS )
" , 36 byte inquiry = " __stringify ( SBP2_WORKAROUND_INQUIRY_36 )
" , skip mode page 8 = " __stringify ( SBP2_WORKAROUND_MODE_SENSE_8 )
" , fix capacity = " __stringify ( SBP2_WORKAROUND_FIX_CAPACITY )
2008-02-04 01:04:38 +03:00
" , delay inquiry = " __stringify ( SBP2_WORKAROUND_DELAY_INQUIRY )
2007-08-13 19:48:25 +04:00
" , override internal blacklist = " __stringify ( SBP2_WORKAROUND_OVERRIDE )
" , or a combination) " ) ;
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 " ;
2007-08-25 16:05:28 +04:00
/*
* We create one struct sbp2_logical_unit per SBP - 2 Logical Unit Number Entry
* and one struct scsi_device per sbp2_logical_unit .
*/
struct sbp2_logical_unit {
struct sbp2_target * tgt ;
struct list_head link ;
struct scsi_device * sdev ;
2006-12-20 03:58:40 +03:00
struct fw_address_handler address_handler ;
struct list_head orb_list ;
2007-08-25 16:05:28 +04:00
2006-12-20 03:58:40 +03:00
u64 command_block_agent_address ;
2007-08-25 16:05:28 +04:00
u16 lun ;
2006-12-20 03:58:40 +03:00
int login_id ;
2007-05-08 04:33:32 +04:00
/*
2007-08-25 16:05:28 +04:00
* The generation is updated once we ' ve logged in or reconnected
* to the logical unit . Thus , I / O to the device will automatically
* fail and get retried if it happens in a window where the device
* is not ready , e . g . after a bus reset but before we reconnect .
2007-05-08 04:33:32 +04:00
*/
2006-12-20 03:58:40 +03:00
int generation ;
2007-02-06 22:49:34 +03:00
int retries ;
struct delayed_work work ;
2006-12-20 03:58:40 +03:00
} ;
2007-08-25 16:05:28 +04:00
/*
* We create one struct sbp2_target per IEEE 1212 Unit Directory
* and one struct Scsi_Host per sbp2_target .
*/
struct sbp2_target {
struct kref kref ;
struct fw_unit * unit ;
2008-02-04 01:09:50 +03:00
const char * bus_id ;
2008-01-26 19:42:45 +03:00
struct list_head lu_list ;
2007-08-25 16:05:28 +04:00
u64 management_agent_address ;
int directory_id ;
int node_id ;
int address_high ;
2008-01-26 19:42:45 +03:00
unsigned int workarounds ;
2008-01-26 07:31:12 +03:00
unsigned int mgt_orb_timeout ;
2007-08-25 16:05:28 +04:00
} ;
2008-01-19 15:15:05 +03:00
/*
* Per section 7.4 .8 of the SBP - 2 spec , a mgt_ORB_timeout value can be
2008-01-26 07:31:12 +03:00
* provided in the config rom . Most devices do provide a value , which
* we ' ll use for login management orbs , but with some sane limits .
2008-01-19 15:15:05 +03:00
*/
2008-01-26 07:31:12 +03:00
# define SBP2_MIN_LOGIN_ORB_TIMEOUT 5000U /* Timeout in ms */
# define SBP2_MAX_LOGIN_ORB_TIMEOUT 40000U /* Timeout in ms */
2008-01-26 19:42:45 +03:00
# define SBP2_ORB_TIMEOUT 2000U /* Timeout in ms */
2006-12-20 03:58:40 +03:00
# define SBP2_ORB_NULL 0x80000000
2008-01-19 15:15:05 +03:00
# define SBP2_MAX_SG_ELEMENT_LENGTH 0xf000
2006-12-20 03:58:40 +03:00
# define SBP2_DIRECTION_TO_MEDIA 0x0
# define SBP2_DIRECTION_FROM_MEDIA 0x1
/* Unit directory keys */
2008-01-26 07:31:12 +03:00
# define SBP2_CSR_UNIT_CHARACTERISTICS 0x3a
2007-08-25 16:05:28 +04:00
# define SBP2_CSR_FIRMWARE_REVISION 0x3c
# define SBP2_CSR_LOGICAL_UNIT_NUMBER 0x14
# define SBP2_CSR_LOGICAL_UNIT_DIRECTORY 0xd4
2006-12-20 03:58:40 +03:00
/* 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 ;
2007-08-25 02:59:58 +04:00
struct kref kref ;
2006-12-20 03:58:40 +03:00
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 ;
2007-08-25 16:05:28 +04:00
struct sbp2_logical_unit * lu ;
2006-12-20 03:58:40 +03:00
2007-07-01 15:55:31 +04:00
struct sbp2_pointer page_table [ SG_ALL ] __attribute__ ( ( aligned ( 8 ) ) ) ;
2006-12-20 03:58:40 +03:00
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 ;
2008-01-26 19:42:45 +03:00
unsigned int workarounds ;
2006-12-20 03:58:40 +03:00
} 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 ,
} ,
2008-02-04 01:04:38 +03:00
/* DViCO Momobay FX-3A with TSB42AA9A bridge */ {
. firmware_revision = 0x002800 ,
. model = 0x000000 ,
. workarounds = SBP2_WORKAROUND_DELAY_INQUIRY ,
} ,
2006-12-20 03:58:40 +03:00
/* 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 ,
}
} ;
2007-08-25 02:59:58 +04:00
static void
free_orb ( struct kref * kref )
{
struct sbp2_orb * orb = container_of ( kref , struct sbp2_orb , kref ) ;
kfree ( orb ) ;
}
2006-12-20 03:58:40 +03:00
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 )
{
2007-08-25 16:05:28 +04:00
struct sbp2_logical_unit * lu = callback_data ;
2006-12-20 03:58:40 +03:00
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 ) ;
2007-08-25 16:05:28 +04:00
list_for_each_entry ( orb , & lu - > orb_list , link ) {
2007-05-08 04:33:35 +04:00
if ( STATUS_GET_ORB_HIGH ( status ) = = 0 & &
2007-08-25 02:59:58 +04:00
STATUS_GET_ORB_LOW ( status ) = = orb - > request_bus ) {
orb - > rcode = RCODE_COMPLETE ;
2006-12-20 03:58:40 +03:00
list_del ( & orb - > link ) ;
break ;
}
}
spin_unlock_irqrestore ( & card - > lock , flags ) ;
2007-08-25 16:05:28 +04:00
if ( & orb - > link ! = & lu - > orb_list )
2006-12-20 03:58:40 +03:00
orb - > callback ( orb , & status ) ;
else
fw_error ( " status write for unknown orb \n " ) ;
2007-08-25 02:59:58 +04:00
kref_put ( & orb - > kref , free_orb ) ;
2006-12-20 03:58:40 +03:00
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 ;
2007-08-25 02:59:58 +04:00
/*
* This is a little tricky . We can get the status write for
* the orb before we get this callback . The status write
* handler above will assume the orb pointer transaction was
* successful and set the rcode to RCODE_COMPLETE for the orb .
* So this callback only sets the rcode if it hasn ' t already
* been set and only does the cleanup if the transaction
* failed and we didn ' t already get a status write .
*/
spin_lock_irqsave ( & card - > lock , flags ) ;
if ( orb - > rcode = = - 1 )
orb - > rcode = rcode ;
if ( orb - > rcode ! = RCODE_COMPLETE ) {
2006-12-20 03:58:40 +03:00
list_del ( & orb - > link ) ;
2007-08-25 12:40:42 +04:00
spin_unlock_irqrestore ( & card - > lock , flags ) ;
2006-12-20 03:58:40 +03:00
orb - > callback ( orb , NULL ) ;
2007-08-25 12:40:42 +04:00
} else {
spin_unlock_irqrestore ( & card - > lock , flags ) ;
2006-12-20 03:58:40 +03:00
}
2007-08-25 02:59:58 +04:00
kref_put ( & orb - > kref , free_orb ) ;
2006-12-20 03:58:40 +03:00
}
static void
2007-08-25 16:05:28 +04:00
sbp2_send_orb ( struct sbp2_orb * orb , struct sbp2_logical_unit * lu ,
2006-12-20 03:58:40 +03:00
int node_id , int generation , u64 offset )
{
2007-08-25 16:05:28 +04:00
struct fw_device * device = fw_device ( lu - > tgt - > unit - > device . parent ) ;
2006-12-20 03:58:40 +03:00
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 ) ;
2007-08-25 16:05:28 +04:00
list_add_tail ( & orb - > link , & lu - > orb_list ) ;
2006-12-20 03:58:40 +03:00
spin_unlock_irqrestore ( & device - > card - > lock , flags ) ;
2007-08-25 02:59:58 +04:00
/* Take a ref for the orb list and for the transaction callback. */
kref_get ( & orb - > kref ) ;
kref_get ( & orb - > kref ) ;
2006-12-20 03:58:40 +03:00
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-08-25 16:05:28 +04:00
static int sbp2_cancel_orbs ( struct sbp2_logical_unit * lu )
2006-12-20 03:58:40 +03:00
{
2007-08-25 16:05:28 +04:00
struct fw_device * device = fw_device ( lu - > tgt - > unit - > device . parent ) ;
2006-12-20 03:58:40 +03:00
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 ) ;
2007-08-25 16:05:28 +04:00
list_splice_init ( & lu - > orb_list , & list ) ;
2006-12-20 03:58:40 +03:00
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
2007-08-25 16:05:28 +04:00
sbp2_send_management_orb ( struct sbp2_logical_unit * lu , int node_id ,
int generation , int function , int lun_or_login_id ,
void * response )
2006-12-20 03:58:40 +03:00
{
2007-08-25 16:05:28 +04:00
struct fw_device * device = fw_device ( lu - > tgt - > unit - > device . parent ) ;
2006-12-20 03:58:40 +03:00
struct sbp2_management_orb * orb ;
2008-01-19 15:15:05 +03:00
unsigned int timeout ;
2006-12-20 03:58:40 +03:00
int retval = - ENOMEM ;
2008-01-27 21:14:44 +03:00
if ( function = = SBP2_LOGOUT_REQUEST & & fw_device_is_shutdown ( device ) )
return 0 ;
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-08-25 02:59:58 +04:00
kref_init ( & orb - > base . kref ) ;
2006-12-20 03:58:40 +03:00
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 ) )
2007-07-02 23:04:44 +04:00
goto fail_mapping_response ;
2006-12-20 03:58:40 +03:00
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 ) |
2007-08-25 16:05:28 +04:00
MANAGEMENT_ORB_LUN ( lun_or_login_id ) ;
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
2007-08-25 16:05:28 +04:00
orb - > request . status_fifo . high = lu - > address_handler . offset > > 32 ;
orb - > request . status_fifo . low = lu - > address_handler . offset ;
2006-12-20 03:58:40 +03:00
if ( function = = SBP2_LOGIN_REQUEST ) {
2008-01-20 03:25:31 +03:00
/* Ask for 2^2 == 4 seconds reconnect grace period */
2006-12-20 03:58:40 +03:00
orb - > request . misc | =
2008-01-20 03:25:31 +03:00
MANAGEMENT_ORB_RECONNECT ( 2 ) |
MANAGEMENT_ORB_EXCLUSIVE ( sbp2_param_exclusive_login ) ;
2008-01-26 07:31:12 +03:00
timeout = lu - > tgt - > mgt_orb_timeout ;
2008-01-19 15:15:05 +03:00
} else {
timeout = SBP2_ORB_TIMEOUT ;
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
2007-07-02 23:04:44 +04:00
orb - > base . request_bus =
dma_map_single ( device - > card - > device , & orb - > request ,
sizeof ( orb - > request ) , DMA_TO_DEVICE ) ;
if ( dma_mapping_error ( orb - > base . request_bus ) )
goto fail_mapping_request ;
2007-08-25 16:05:28 +04:00
sbp2_send_orb ( & orb - > base , lu , node_id , generation ,
lu - > tgt - > management_agent_address ) ;
2006-12-20 03:58:40 +03:00
2008-01-19 15:15:05 +03:00
wait_for_completion_timeout ( & orb - > done , msecs_to_jiffies ( timeout ) ) ;
2006-12-20 03:58:40 +03:00
retval = - EIO ;
2007-08-25 16:05:28 +04:00
if ( sbp2_cancel_orbs ( lu ) = = 0 ) {
2008-02-04 01:09:50 +03:00
fw_error ( " %s: orb reply timed out, rcode=0x%02x \n " ,
lu - > tgt - > bus_id , orb - > base . rcode ) ;
2006-12-20 03:58:40 +03:00
goto out ;
}
2007-03-07 20:12:47 +03:00
if ( orb - > base . rcode ! = RCODE_COMPLETE ) {
2008-02-04 01:09:50 +03:00
fw_error ( " %s: management write failed, rcode 0x%02x \n " ,
lu - > tgt - > bus_id , orb - > base . rcode ) ;
2006-12-20 03:58:40 +03:00
goto out ;
}
2007-05-08 04:33:35 +04:00
if ( STATUS_GET_RESPONSE ( orb - > status ) ! = 0 | |
STATUS_GET_SBP_STATUS ( orb - > status ) ! = 0 ) {
2008-02-04 01:09:50 +03:00
fw_error ( " %s: error status: %d:%d \n " , lu - > tgt - > bus_id ,
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 ) ;
2007-07-02 23:04:44 +04:00
fail_mapping_request :
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 ) ;
2007-07-02 23:04:44 +04:00
fail_mapping_response :
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 ) ) ;
2007-08-25 02:59:58 +04:00
kref_put ( & orb - > base . kref , free_orb ) ;
2006-12-20 03:58:40 +03:00
return retval ;
}
static void
complete_agent_reset_write ( struct fw_card * card , int rcode ,
2008-02-04 01:08:58 +03:00
void * payload , size_t length , void * done )
2006-12-20 03:58:40 +03:00
{
2008-02-04 01:08:58 +03:00
complete ( done ) ;
}
static void sbp2_agent_reset ( struct sbp2_logical_unit * lu )
{
struct fw_device * device = fw_device ( lu - > tgt - > unit - > device . parent ) ;
DECLARE_COMPLETION_ONSTACK ( done ) ;
struct fw_transaction t ;
static u32 z ;
2006-12-20 03:58:40 +03:00
2008-02-04 01:08:58 +03:00
fw_send_request ( device - > card , & t , TCODE_WRITE_QUADLET_REQUEST ,
lu - > tgt - > node_id , lu - > generation , device - > max_speed ,
lu - > command_block_agent_address + SBP2_AGENT_RESET ,
& z , sizeof ( z ) , complete_agent_reset_write , & done ) ;
wait_for_completion ( & done ) ;
2006-12-20 03:58:40 +03:00
}
2008-02-04 01:08:58 +03:00
static void
complete_agent_reset_write_no_wait ( struct fw_card * card , int rcode ,
void * payload , size_t length , void * data )
{
kfree ( data ) ;
}
static void sbp2_agent_reset_no_wait ( struct sbp2_logical_unit * lu )
2006-12-20 03:58:40 +03:00
{
2007-08-25 16:05:28 +04:00
struct fw_device * device = fw_device ( lu - > tgt - > unit - > device . parent ) ;
2006-12-20 03:58:40 +03:00
struct fw_transaction * t ;
2008-02-04 01:08:58 +03:00
static u32 z ;
2006-12-20 03:58:40 +03:00
2008-02-04 01:08:58 +03:00
t = kmalloc ( sizeof ( * t ) , GFP_ATOMIC ) ;
2006-12-20 03:58:40 +03:00
if ( t = = NULL )
2008-02-04 01:08:58 +03:00
return ;
2006-12-20 03:58:40 +03:00
fw_send_request ( device - > card , t , TCODE_WRITE_QUADLET_REQUEST ,
2007-08-25 16:05:28 +04:00
lu - > tgt - > node_id , lu - > generation , device - > max_speed ,
lu - > command_block_agent_address + SBP2_AGENT_RESET ,
2008-02-04 01:08:58 +03:00
& z , sizeof ( z ) , complete_agent_reset_write_no_wait , t ) ;
2006-12-20 03:58:40 +03:00
}
2007-08-25 16:05:28 +04:00
static void sbp2_release_target ( struct kref * kref )
2007-03-15 00:34:58 +03:00
{
2007-08-25 16:05:28 +04:00
struct sbp2_target * tgt = container_of ( kref , struct sbp2_target , kref ) ;
struct sbp2_logical_unit * lu , * next ;
struct Scsi_Host * shost =
container_of ( ( void * ) tgt , struct Scsi_Host , hostdata [ 0 ] ) ;
list_for_each_entry_safe ( lu , next , & tgt - > lu_list , link ) {
if ( lu - > sdev )
scsi_remove_device ( lu - > sdev ) ;
2008-01-27 21:14:44 +03:00
sbp2_send_management_orb ( lu , tgt - > node_id , lu - > generation ,
SBP2_LOGOUT_REQUEST , lu - > login_id , NULL ) ;
2008-01-20 03:24:26 +03:00
2007-08-25 16:05:28 +04:00
fw_core_remove_address_handler ( & lu - > address_handler ) ;
list_del ( & lu - > link ) ;
kfree ( lu ) ;
}
scsi_remove_host ( shost ) ;
2008-02-04 01:09:50 +03:00
fw_notify ( " released %s \n " , tgt - > bus_id ) ;
2007-08-25 16:05:28 +04:00
put_device ( & tgt - > unit - > device ) ;
scsi_host_put ( shost ) ;
2007-03-15 00:34:58 +03:00
}
2007-08-12 14:51:18 +04:00
static struct workqueue_struct * sbp2_wq ;
2007-11-07 03:12:51 +03:00
/*
* Always get the target ' s kref when scheduling work on one its units .
* Each workqueue job is responsible to call sbp2_target_put ( ) upon return .
*/
static void sbp2_queue_work ( struct sbp2_logical_unit * lu , unsigned long delay )
{
if ( queue_delayed_work ( sbp2_wq , & lu - > work , delay ) )
kref_get ( & lu - > tgt - > kref ) ;
}
static void sbp2_target_put ( struct sbp2_target * tgt )
{
kref_put ( & tgt - > kref , sbp2_release_target ) ;
}
2007-08-25 16:05:28 +04:00
static void sbp2_reconnect ( struct work_struct * work ) ;
2007-02-06 22:49:34 +03:00
static void sbp2_login ( struct work_struct * work )
{
2007-08-25 16:05:28 +04:00
struct sbp2_logical_unit * lu =
container_of ( work , struct sbp2_logical_unit , work . work ) ;
2008-02-04 01:09:50 +03:00
struct sbp2_target * tgt = lu - > tgt ;
struct fw_device * device = fw_device ( tgt - > unit - > device . parent ) ;
struct Scsi_Host * shost ;
2007-08-25 16:05:28 +04:00
struct scsi_device * sdev ;
struct scsi_lun eight_bytes_lun ;
2007-02-06 22:49:34 +03:00
struct sbp2_login_response response ;
2007-08-25 16:05:28 +04:00
int generation , node_id , local_node_id ;
2007-02-06 22:49:34 +03:00
2008-01-27 21:14:44 +03:00
if ( fw_device_is_shutdown ( device ) )
goto out ;
2008-01-24 03:53:19 +03:00
generation = device - > generation ;
2008-01-25 20:57:41 +03:00
smp_rmb ( ) ; /* node_id must not be older than generation */
2008-01-24 03:53:19 +03:00
node_id = device - > node_id ;
local_node_id = device - > card - > node_id ;
2007-02-06 22:49:34 +03:00
2008-02-04 01:11:39 +03:00
/* If this is a re-login attempt, log out, or we might be rejected. */
if ( lu - > sdev )
sbp2_send_management_orb ( lu , device - > node_id , generation ,
SBP2_LOGOUT_REQUEST , lu - > login_id , NULL ) ;
2007-08-25 16:05:28 +04:00
if ( sbp2_send_management_orb ( lu , node_id , generation ,
SBP2_LOGIN_REQUEST , lu - > lun , & response ) < 0 ) {
2007-11-07 03:12:51 +03:00
if ( lu - > retries + + < 5 )
sbp2_queue_work ( lu , DIV_ROUND_UP ( HZ , 5 ) ) ;
else
2008-02-04 01:09:50 +03:00
fw_error ( " %s: failed to login to LUN %04x \n " ,
tgt - > bus_id , lu - > lun ) ;
2007-11-07 03:12:51 +03:00
goto out ;
2007-02-06 22:49:34 +03:00
}
2008-02-04 01:09:50 +03:00
lu - > generation = generation ;
tgt - > node_id = node_id ;
tgt - > address_high = local_node_id < < 16 ;
2007-02-06 22:49:34 +03:00
/* Get command block agent offset and login id. */
2007-08-25 16:05:28 +04:00
lu - > 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-08-25 16:05:28 +04:00
lu - > login_id = LOGIN_RESPONSE_GET_LOGIN_ID ( response ) ;
2007-02-06 22:49:34 +03:00
2008-02-04 01:09:50 +03:00
fw_notify ( " %s: logged in to LUN %04x (%d retries) \n " ,
tgt - > bus_id , lu - > lun , lu - > retries ) ;
2007-02-06 22:49:34 +03:00
#if 0
/* FIXME: The linux1394 sbp2 does this last step. */
sbp2_set_busy_timeout ( scsi_id ) ;
# endif
2007-08-25 16:05:28 +04:00
PREPARE_DELAYED_WORK ( & lu - > work , sbp2_reconnect ) ;
sbp2_agent_reset ( lu ) ;
2008-02-04 01:10:47 +03:00
/* This was a re-login. */
if ( lu - > sdev ) {
sbp2_cancel_orbs ( lu ) ;
goto out ;
}
2008-02-04 01:04:38 +03:00
if ( lu - > tgt - > workarounds & SBP2_WORKAROUND_DELAY_INQUIRY )
ssleep ( SBP2_INQUIRY_DELAY ) ;
2007-08-25 16:05:28 +04:00
memset ( & eight_bytes_lun , 0 , sizeof ( eight_bytes_lun ) ) ;
eight_bytes_lun . scsi_lun [ 0 ] = ( lu - > lun > > 8 ) & 0xff ;
eight_bytes_lun . scsi_lun [ 1 ] = lu - > lun & 0xff ;
2008-02-04 01:09:50 +03:00
shost = container_of ( ( void * ) tgt , struct Scsi_Host , hostdata [ 0 ] ) ;
2007-02-06 22:49:34 +03:00
2007-08-25 16:05:28 +04:00
sdev = __scsi_add_device ( shost , 0 , 0 ,
scsilun_to_int ( & eight_bytes_lun ) , lu ) ;
2008-02-15 23:29:02 +03:00
/*
* FIXME : We are unable to perform reconnects while in sbp2_login ( ) .
* Therefore __scsi_add_device ( ) will get into trouble if a bus reset
* happens in parallel . It will either fail or leave us with an
* unusable sdev . As a workaround we check for this and retry the
* whole login and SCSI probing .
*/
2008-01-26 19:43:23 +03:00
2008-02-15 23:29:02 +03:00
/* Reported error during __scsi_add_device() */
if ( IS_ERR ( sdev ) )
goto out_logout_login ;
scsi_device_put ( sdev ) ;
/* Unreported error during __scsi_add_device() */
smp_rmb ( ) ; /* get current card generation */
if ( generation ! = device - > card - > generation ) {
scsi_remove_device ( sdev ) ;
goto out_logout_login ;
2007-02-06 22:49:34 +03:00
}
2008-02-15 23:29:02 +03:00
/* No error during __scsi_add_device() */
lu - > sdev = sdev ;
goto out ;
out_logout_login :
smp_rmb ( ) ; /* generation may have changed */
generation = device - > generation ;
smp_rmb ( ) ; /* node_id must not be older than generation */
sbp2_send_management_orb ( lu , device - > node_id , generation ,
SBP2_LOGOUT_REQUEST , lu - > login_id , NULL ) ;
/*
* If a bus reset happened , sbp2_update will have requeued
* lu - > work already . Reset the work from reconnect to login .
*/
PREPARE_DELAYED_WORK ( & lu - > work , sbp2_login ) ;
2007-11-07 03:12:51 +03:00
out :
2008-02-04 01:09:50 +03:00
sbp2_target_put ( tgt ) ;
2007-02-06 22:49:34 +03:00
}
2006-12-20 03:58:40 +03:00
2007-08-25 16:05:28 +04:00
static int sbp2_add_logical_unit ( struct sbp2_target * tgt , int lun_entry )
2006-12-20 03:58:40 +03:00
{
2007-08-25 16:05:28 +04:00
struct sbp2_logical_unit * lu ;
2006-12-20 03:58:40 +03:00
2007-08-25 16:05:28 +04:00
lu = kmalloc ( sizeof ( * lu ) , GFP_KERNEL ) ;
if ( ! lu )
return - ENOMEM ;
2006-12-20 03:58:40 +03:00
2007-08-25 16:05:28 +04:00
lu - > address_handler . length = 0x100 ;
lu - > address_handler . address_callback = sbp2_status_write ;
lu - > address_handler . callback_data = lu ;
2006-12-20 03:58:40 +03:00
2007-08-25 16:05:28 +04:00
if ( fw_core_add_address_handler ( & lu - > address_handler ,
& fw_high_memory_region ) < 0 ) {
kfree ( lu ) ;
return - ENOMEM ;
}
2006-12-20 03:58:40 +03:00
2007-08-25 16:05:28 +04:00
lu - > tgt = tgt ;
lu - > sdev = NULL ;
lu - > lun = lun_entry & 0xffff ;
lu - > retries = 0 ;
INIT_LIST_HEAD ( & lu - > orb_list ) ;
INIT_DELAYED_WORK ( & lu - > work , sbp2_login ) ;
2006-12-20 03:58:40 +03:00
2007-08-25 16:05:28 +04:00
list_add_tail ( & lu - > link , & tgt - > lu_list ) ;
return 0 ;
}
2007-05-10 03:23:07 +04:00
2007-08-25 16:05:28 +04:00
static int sbp2_scan_logical_unit_dir ( struct sbp2_target * tgt , u32 * directory )
{
struct fw_csr_iterator ci ;
int key , value ;
2006-12-20 03:58:40 +03:00
2007-08-25 16:05:28 +04:00
fw_csr_iterator_init ( & ci , directory ) ;
while ( fw_csr_iterator_next ( & ci , & key , & value ) )
if ( key = = SBP2_CSR_LOGICAL_UNIT_NUMBER & &
sbp2_add_logical_unit ( tgt , value ) < 0 )
return - ENOMEM ;
return 0 ;
}
static int sbp2_scan_unit_dir ( struct sbp2_target * tgt , u32 * directory ,
u32 * model , u32 * firmware_revision )
{
struct fw_csr_iterator ci ;
int key , value ;
2008-01-26 07:31:12 +03:00
unsigned int timeout ;
2007-08-25 16:05:28 +04:00
fw_csr_iterator_init ( & ci , directory ) ;
2006-12-20 03:58:40 +03:00
while ( fw_csr_iterator_next ( & ci , & key , & value ) ) {
switch ( key ) {
2007-08-25 16:05:28 +04:00
2006-12-20 03:58:40 +03:00
case CSR_DEPENDENT_INFO | CSR_OFFSET :
2007-08-25 16:05:28 +04:00
tgt - > management_agent_address =
CSR_REGISTER_BASE + 4 * value ;
2006-12-20 03:58:40 +03:00
break ;
2007-08-25 16:05:28 +04:00
case CSR_DIRECTORY_ID :
tgt - > directory_id = value ;
2006-12-20 03:58:40 +03:00
break ;
2007-08-25 16:05:28 +04:00
2006-12-20 03:58:40 +03:00
case CSR_MODEL :
2007-08-25 16:05:28 +04:00
* model = value ;
break ;
case SBP2_CSR_FIRMWARE_REVISION :
* firmware_revision = value ;
break ;
2008-01-26 07:31:12 +03:00
case SBP2_CSR_UNIT_CHARACTERISTICS :
/* the timeout value is stored in 500ms units */
timeout = ( ( unsigned int ) value > > 8 & 0xff ) * 500 ;
timeout = max ( timeout , SBP2_MIN_LOGIN_ORB_TIMEOUT ) ;
tgt - > mgt_orb_timeout =
min ( timeout , SBP2_MAX_LOGIN_ORB_TIMEOUT ) ;
if ( timeout > tgt - > mgt_orb_timeout )
fw_notify ( " %s: config rom contains %ds "
" management ORB timeout, limiting "
2008-02-04 01:09:50 +03:00
" to %ds \n " , tgt - > bus_id ,
2008-01-26 07:31:12 +03:00
timeout / 1000 ,
tgt - > mgt_orb_timeout / 1000 ) ;
break ;
2007-08-25 16:05:28 +04:00
case SBP2_CSR_LOGICAL_UNIT_NUMBER :
if ( sbp2_add_logical_unit ( tgt , value ) < 0 )
return - ENOMEM ;
break ;
case SBP2_CSR_LOGICAL_UNIT_DIRECTORY :
if ( sbp2_scan_logical_unit_dir ( tgt , ci . p + value ) < 0 )
return - ENOMEM ;
2006-12-20 03:58:40 +03:00
break ;
}
}
2007-08-25 16:05:28 +04:00
return 0 ;
}
static void sbp2_init_workarounds ( struct sbp2_target * tgt , u32 model ,
u32 firmware_revision )
{
int i ;
2008-01-26 19:42:45 +03:00
unsigned int w = sbp2_param_workarounds ;
2007-08-13 19:48:25 +04:00
if ( w )
fw_notify ( " Please notify linux1394-devel@lists.sourceforge.net "
" if you need the workarounds parameter for %s \n " ,
2008-02-04 01:09:50 +03:00
tgt - > bus_id ) ;
2007-08-25 16:05:28 +04:00
2007-08-13 19:48:25 +04:00
if ( w & SBP2_WORKAROUND_OVERRIDE )
goto out ;
2006-12-20 03:58:40 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( sbp2_workarounds_table ) ; i + + ) {
2007-08-25 16:05:28 +04:00
2006-12-20 03:58:40 +03:00
if ( sbp2_workarounds_table [ i ] . firmware_revision ! =
( firmware_revision & 0xffffff00 ) )
continue ;
2007-08-25 16:05:28 +04:00
2006-12-20 03:58:40 +03:00
if ( sbp2_workarounds_table [ i ] . model ! = model & &
sbp2_workarounds_table [ i ] . model ! = ~ 0 )
continue ;
2007-08-25 16:05:28 +04:00
2007-08-13 19:48:25 +04:00
w | = sbp2_workarounds_table [ i ] . workarounds ;
2006-12-20 03:58:40 +03:00
break ;
}
2007-08-13 19:48:25 +04:00
out :
if ( w )
2007-08-25 16:05:28 +04:00
fw_notify ( " Workarounds for %s: 0x%x "
2006-12-20 03:58:40 +03:00
" (firmware_revision 0x%06x, model_id 0x%06x) \n " ,
2008-02-04 01:09:50 +03:00
tgt - > bus_id , w , firmware_revision , model ) ;
2007-08-13 19:48:25 +04:00
tgt - > workarounds = w ;
2007-08-25 16:05:28 +04:00
}
static struct scsi_host_template scsi_driver_template ;
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_target * tgt ;
struct sbp2_logical_unit * lu ;
struct Scsi_Host * shost ;
u32 model , firmware_revision ;
shost = scsi_host_alloc ( & scsi_driver_template , sizeof ( * tgt ) ) ;
if ( shost = = NULL )
return - ENOMEM ;
tgt = ( struct sbp2_target * ) shost - > hostdata ;
unit - > device . driver_data = tgt ;
tgt - > unit = unit ;
kref_init ( & tgt - > kref ) ;
INIT_LIST_HEAD ( & tgt - > lu_list ) ;
2008-02-04 01:09:50 +03:00
tgt - > bus_id = unit - > device . bus_id ;
2007-08-25 16:05:28 +04:00
if ( fw_device_enable_phys_dma ( device ) < 0 )
goto fail_shost_put ;
if ( scsi_add_host ( shost , & unit - > device ) < 0 )
goto fail_shost_put ;
/* Initialize to values that won't match anything in our table. */
firmware_revision = 0xff000000 ;
model = 0xff000000 ;
/* implicit directory ID */
tgt - > directory_id = ( ( unit - > directory - device - > config_rom ) * 4
+ CSR_CONFIG_ROM ) & 0xffffff ;
if ( sbp2_scan_unit_dir ( tgt , unit - > directory , & model ,
& firmware_revision ) < 0 )
goto fail_tgt_put ;
sbp2_init_workarounds ( tgt , model , firmware_revision ) ;
2006-12-20 03:58:40 +03:00
2007-03-15 00:34:58 +03:00
get_device ( & unit - > device ) ;
2007-11-07 03:12:51 +03:00
/* Do the login in a workqueue so we can easily reschedule retries. */
2007-08-25 16:05:28 +04:00
list_for_each_entry ( lu , & tgt - > lu_list , link )
2007-11-07 03:12:51 +03:00
sbp2_queue_work ( lu , 0 ) ;
2006-12-20 03:58:40 +03:00
return 0 ;
2007-05-10 03:23:07 +04:00
2007-08-25 16:05:28 +04:00
fail_tgt_put :
2007-11-07 03:12:51 +03:00
sbp2_target_put ( tgt ) ;
2007-08-25 16:05:28 +04:00
return - ENOMEM ;
fail_shost_put :
scsi_host_put ( shost ) ;
return - ENOMEM ;
2006-12-20 03:58:40 +03:00
}
static int sbp2_remove ( struct device * dev )
{
struct fw_unit * unit = fw_unit ( dev ) ;
2007-08-25 16:05:28 +04:00
struct sbp2_target * tgt = unit - > device . driver_data ;
2006-12-20 03:58:40 +03:00
2007-11-07 03:12:51 +03:00
sbp2_target_put ( tgt ) ;
2006-12-20 03:58:40 +03:00
return 0 ;
}
static void sbp2_reconnect ( struct work_struct * work )
{
2007-08-25 16:05:28 +04:00
struct sbp2_logical_unit * lu =
container_of ( work , struct sbp2_logical_unit , work . work ) ;
2008-02-04 01:09:50 +03:00
struct sbp2_target * tgt = lu - > tgt ;
struct fw_device * device = fw_device ( tgt - > unit - > device . parent ) ;
2006-12-20 03:58:40 +03:00
int generation , node_id , local_node_id ;
2008-01-27 21:14:44 +03:00
if ( fw_device_is_shutdown ( device ) )
goto out ;
2008-01-24 03:53:19 +03:00
generation = device - > generation ;
2008-01-25 20:57:41 +03:00
smp_rmb ( ) ; /* node_id must not be older than generation */
2008-01-24 03:53:19 +03:00
node_id = device - > node_id ;
local_node_id = device - > card - > node_id ;
2006-12-20 03:58:40 +03:00
2007-08-25 16:05:28 +04:00
if ( sbp2_send_management_orb ( lu , node_id , generation ,
2007-02-06 22:49:34 +03:00
SBP2_RECONNECT_REQUEST ,
2007-08-25 16:05:28 +04:00
lu - > login_id , NULL ) < 0 ) {
2008-02-04 01:11:39 +03:00
/*
* If reconnect was impossible even though we are in the
* current generation , fall back and try to log in again .
*
* We could check for " Function rejected " status , but
* looking at the bus generation as simpler and more general .
*/
smp_rmb ( ) ; /* get current card generation */
if ( generation = = device - > card - > generation | |
lu - > retries + + > = 5 ) {
2008-02-04 01:09:50 +03:00
fw_error ( " %s: failed to reconnect \n " , tgt - > bus_id ) ;
2007-08-25 16:05:28 +04:00
lu - > retries = 0 ;
PREPARE_DELAYED_WORK ( & lu - > work , sbp2_login ) ;
2007-02-06 22:49:34 +03:00
}
2007-11-07 03:12:51 +03:00
sbp2_queue_work ( lu , DIV_ROUND_UP ( HZ , 5 ) ) ;
goto out ;
2007-02-06 22:49:34 +03:00
}
2006-12-20 03:58:40 +03:00
2008-02-04 01:09:50 +03:00
lu - > generation = generation ;
tgt - > node_id = node_id ;
tgt - > address_high = local_node_id < < 16 ;
2007-02-06 22:49:34 +03:00
2008-02-04 01:09:50 +03:00
fw_notify ( " %s: reconnected to LUN %04x (%d retries) \n " ,
tgt - > bus_id , lu - > lun , lu - > retries ) ;
2007-08-25 16:05:28 +04:00
sbp2_agent_reset ( lu ) ;
sbp2_cancel_orbs ( lu ) ;
2007-11-07 03:12:51 +03:00
out :
2008-02-04 01:09:50 +03:00
sbp2_target_put ( tgt ) ;
2006-12-20 03:58:40 +03:00
}
static void sbp2_update ( struct fw_unit * unit )
{
2007-08-25 16:05:28 +04:00
struct sbp2_target * tgt = unit - > device . driver_data ;
struct sbp2_logical_unit * lu ;
2006-12-20 03:58:40 +03:00
2007-08-25 16:05:28 +04:00
fw_device_enable_phys_dma ( fw_device ( unit - > device . parent ) ) ;
/*
* Fw - core serializes sbp2_update ( ) against sbp2_remove ( ) .
* Iteration over tgt - > lu_list is therefore safe here .
*/
list_for_each_entry ( lu , & tgt - > lu_list , link ) {
lu - > retries = 0 ;
2007-11-07 03:12:51 +03:00
sbp2_queue_work ( lu , 0 ) ;
2007-08-25 16:05:28 +04:00
}
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 ) ;
2007-08-25 16:05:28 +04:00
struct fw_device * device = fw_device ( orb - > lu - > tgt - > unit - > device . parent ) ;
2006-12-20 03:58:40 +03:00
int result ;
if ( status ! = NULL ) {
2007-05-08 04:33:35 +04:00
if ( STATUS_GET_DEAD ( * status ) )
2008-02-04 01:08:58 +03:00
sbp2_agent_reset_no_wait ( orb - > lu ) ;
2006-12-20 03:58:40 +03:00
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
2007-07-16 23:05:41 +04:00
if ( scsi_sg_count ( orb - > cmd ) > 0 )
dma_unmap_sg ( device - > card - > device , scsi_sglist ( orb - > cmd ) ,
scsi_sg_count ( orb - > cmd ) ,
2006-12-20 03:58:40 +03:00
orb - > cmd - > sc_data_direction ) ;
if ( orb - > page_table_bus ! = 0 )
dma_unmap_single ( device - > card - > device , orb - > page_table_bus ,
2007-07-03 00:07:34 +04:00
sizeof ( orb - > page_table ) , 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 ) ;
}
2007-08-25 16:05:28 +04:00
static int
sbp2_map_scatterlist ( struct sbp2_command_orb * orb , struct fw_device * device ,
struct sbp2_logical_unit * lu )
2006-12-20 03:58:40 +03:00
{
struct scatterlist * sg ;
int sg_len , l , i , j , count ;
dma_addr_t sg_addr ;
2007-07-16 23:05:41 +04:00
sg = scsi_sglist ( orb - > cmd ) ;
count = dma_map_sg ( device - > card - > device , sg , scsi_sg_count ( orb - > cmd ) ,
2006-12-20 03:58:40 +03:00
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 ) {
2007-08-25 16:05:28 +04:00
orb - > request . data_descriptor . high = lu - > tgt - > address_high ;
2006-12-20 03:58:40 +03:00
orb - > request . data_descriptor . low = sg_dma_address ( sg ) ;
2007-08-25 16:05:28 +04:00
orb - > request . misc | = 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
*/
2008-01-15 23:10:50 +03:00
for ( i = 0 , j = 0 ; i < count ; i + + , sg = sg_next ( sg ) ) {
sg_len = sg_dma_len ( sg ) ;
sg_addr = sg_dma_address ( sg ) ;
2006-12-20 03:58:40 +03:00
while ( sg_len ) {
2007-07-01 15:56:03 +04:00
/* FIXME: This won't get us out of the pinch. */
if ( unlikely ( j > = ARRAY_SIZE ( orb - > page_table ) ) ) {
fw_error ( " page table overflow \n " ) ;
goto fail_page_table ;
}
2006-12-20 03:58:40 +03:00
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-07-03 00:07:34 +04:00
fw_memcpy_to_be32 ( orb - > page_table , orb - > page_table ,
sizeof ( orb - > page_table [ 0 ] ) * j ) ;
orb - > page_table_bus =
dma_map_single ( device - > card - > device , orb - > page_table ,
sizeof ( orb - > page_table ) , DMA_TO_DEVICE ) ;
if ( dma_mapping_error ( orb - > page_table_bus ) )
goto fail_page_table ;
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 .
*/
2007-08-25 16:05:28 +04:00
orb - > request . data_descriptor . high = lu - > tgt - > address_high ;
2006-12-20 03:58:40 +03:00
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
2007-05-10 03:23:08 +04:00
return 0 ;
fail_page_table :
2007-07-16 23:05:41 +04:00
dma_unmap_sg ( device - > card - > device , sg , scsi_sg_count ( orb - > cmd ) ,
2007-05-10 03:23:08 +04:00
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-08-25 16:05:28 +04:00
struct sbp2_logical_unit * lu = cmd - > device - > hostdata ;
struct fw_device * device = fw_device ( lu - > tgt - > unit - > device . parent ) ;
2006-12-20 03:58:40 +03:00
struct sbp2_command_orb * orb ;
2008-01-26 19:42:45 +03:00
unsigned int max_payload ;
2007-08-25 16:05:28 +04:00
int retval = SCSI_MLQUEUE_HOST_BUSY ;
2006-12-20 03:58:40 +03:00
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-08-25 16:05:28 +04:00
return SCSI_MLQUEUE_HOST_BUSY ;
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 ;
2007-08-25 02:59:58 +04:00
kref_init ( & orb - > base . kref ) ;
2006-12-20 03:58:40 +03:00
2007-08-25 16:05:28 +04:00
orb - > lu = lu ;
2006-12-20 03:58:40 +03:00
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 .
*/
2007-07-22 00:43:05 +04:00
max_payload = min ( device - > max_speed + 7 ,
device - > card - > max_receive - 1 ) ;
2006-12-20 03:58:40 +03:00
orb - > request . misc =
2007-07-22 00:43:05 +04:00
COMMAND_ORB_MAX_PAYLOAD ( max_payload ) |
2007-06-10 23:31:36 +04:00
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-08-25 16:05:28 +04:00
if ( scsi_sg_count ( cmd ) & & sbp2_map_scatterlist ( orb , device , lu ) < 0 )
goto out ;
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 ;
2007-07-02 23:04:08 +04:00
orb - > base . request_bus =
dma_map_single ( device - > card - > device , & orb - > request ,
sizeof ( orb - > request ) , DMA_TO_DEVICE ) ;
if ( dma_mapping_error ( orb - > base . request_bus ) )
2007-08-25 16:05:28 +04:00
goto out ;
2007-02-06 22:49:40 +03:00
2007-08-25 16:05:28 +04:00
sbp2_send_orb ( & orb - > base , lu , lu - > tgt - > node_id , lu - > generation ,
lu - > command_block_agent_address + SBP2_ORB_POINTER ) ;
retval = 0 ;
out :
2007-08-25 02:59:58 +04:00
kref_put ( & orb - > base . kref , free_orb ) ;
2007-08-25 16:05:28 +04:00
return retval ;
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-08-25 16:05:28 +04:00
struct sbp2_logical_unit * lu = sdev - > hostdata ;
2007-01-23 23:20:08 +03:00
sdev - > allow_restart = 1 ;
2008-01-01 19:00:10 +03:00
/*
* Update the dma alignment ( minimum alignment requirements for
* start and end of DMA transfers ) to be a sector
*/
blk_queue_update_dma_alignment ( sdev - > request_queue , 511 ) ;
2007-08-25 16:05:28 +04:00
if ( lu - > tgt - > workarounds & SBP2_WORKAROUND_INQUIRY_36 )
2007-01-23 23:20:08 +03:00
sdev - > inquiry_len = 36 ;
2007-08-25 16:05:28 +04:00
2007-01-23 23:20:08 +03:00
return 0 ;
}
2006-12-20 03:58:40 +03:00
static int sbp2_scsi_slave_configure ( struct scsi_device * sdev )
{
2007-08-25 16:05:28 +04:00
struct sbp2_logical_unit * lu = sdev - > hostdata ;
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 ;
2007-08-25 16:05:28 +04:00
2006-12-20 03:58:40 +03:00
if ( sdev - > type = = TYPE_DISK & &
2007-08-25 16:05:28 +04:00
lu - > tgt - > workarounds & SBP2_WORKAROUND_MODE_SENSE_8 )
2006-12-20 03:58:40 +03:00
sdev - > skip_ms_page_8 = 1 ;
2007-08-25 16:05:28 +04:00
if ( lu - > tgt - > workarounds & SBP2_WORKAROUND_FIX_CAPACITY )
2006-12-20 03:58:40 +03:00
sdev - > fix_capacity = 1 ;
2007-08-25 16:05:28 +04:00
if ( lu - > tgt - > workarounds & SBP2_WORKAROUND_128K_MAX_TRANS )
2007-06-18 01:52:08 +04:00
blk_queue_max_sectors ( sdev - > request_queue , 128 * 1024 / 512 ) ;
2007-08-25 16:05:28 +04:00
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-08-25 16:05:28 +04:00
struct sbp2_logical_unit * lu = cmd - > device - > hostdata ;
2006-12-20 03:58:40 +03:00
2008-02-04 01:09:50 +03:00
fw_notify ( " %s: sbp2_scsi_abort \n " , lu - > tgt - > bus_id ) ;
2007-08-25 16:05:28 +04:00
sbp2_agent_reset ( lu ) ;
sbp2_cancel_orbs ( lu ) ;
2006-12-20 03:58:40 +03:00
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 ) ;
2007-08-25 16:05:28 +04:00
struct sbp2_logical_unit * lu ;
2007-05-27 15:18:27 +04:00
struct fw_device * device ;
if ( ! sdev )
return 0 ;
2007-08-25 16:05:28 +04:00
lu = sdev - > hostdata ;
device = fw_device ( lu - > tgt - > unit - > device . parent ) ;
2007-05-27 15:18:27 +04:00
return sprintf ( buf , " %08x%08x:%06x:%04x \n " ,
device - > config_rom [ 3 ] , device - > config_rom [ 4 ] ,
2007-08-25 16:05:28 +04:00
lu - > tgt - > directory_id , lu - > lun ) ;
2007-05-27 15:18:27 +04:00
}
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 " ,
2007-05-10 03:23:12 +04:00
. proc_name = sbp2_driver_name ,
2006-12-20 03:58:40 +03:00
. 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 )
{
2007-08-12 14:51:18 +04:00
sbp2_wq = create_singlethread_workqueue ( KBUILD_MODNAME ) ;
if ( ! sbp2_wq )
return - ENOMEM ;
2006-12-20 03:58:40 +03:00
return driver_register ( & sbp2_driver . driver ) ;
}
static void __exit sbp2_cleanup ( void )
{
driver_unregister ( & sbp2_driver . driver ) ;
2007-08-12 14:51:18 +04:00
destroy_workqueue ( sbp2_wq ) ;
2006-12-20 03:58:40 +03:00
}
module_init ( sbp2_init ) ;
module_exit ( sbp2_cleanup ) ;