2005-04-16 15:20:36 -07:00
/*
* sbp2 . c - SBP - 2 protocol driver for IEEE - 1394
*
* Copyright ( C ) 2000 James Goodwin , Filanet Corporation ( www . filanet . com )
* jamesg @ filanet . com ( JSG )
*
* Copyright ( C ) 2003 Ben Collins < bcollins @ debian . org >
*
* 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 .
*/
/*
* Brief Description :
*
* This driver implements the Serial Bus Protocol 2 ( SBP - 2 ) over IEEE - 1394
* under Linux . The SBP - 2 driver is implemented as an IEEE - 1394 high - level
* driver . It also registers as a SCSI lower - level driver in order to accept
* SCSI commands for transport using SBP - 2.
*
2006-11-02 21:16:08 +01:00
* You may access any attached SBP - 2 ( usually storage devices ) as regular
* SCSI devices . E . g . mount / dev / sda1 , fdisk , mkfs , etc . .
2005-04-16 15:20:36 -07:00
*
2006-11-02 21:16:08 +01:00
* See http : //www.t10.org/drafts.htm#sbp2 for the final draft of the SBP-2
* specification and for where to purchase the official standard .
2005-04-16 15:20:36 -07:00
*
2006-11-02 21:16:08 +01:00
* TODO :
* - look into possible improvements of the SCSI error handlers
* - handle Unit_Characteristics . mgt_ORB_timeout and . ORB_size
* - handle Logical_Unit_Number . ordered
* - handle src = = 1 in status blocks
* - reimplement the DMA mapping in absence of physical DMA so that
* bus_to_virt is no longer required
* - debug the handling of absent physical DMA
* - replace CONFIG_IEEE1394_SBP2_PHYS_DMA by automatic detection
* ( this is easy but depends on the previous two TODO items )
* - make the parameter serialize_io configurable per device
* - move all requests to fetch agent registers into non - atomic context ,
* replace all usages of sbp2util_node_write_no_wait by true transactions
* Grep for inline FIXME comments below .
2005-04-16 15:20:36 -07:00
*/
2007-12-16 17:31:26 +01:00
# include <linux/blkdev.h>
2006-08-14 18:56:00 +02:00
# include <linux/compiler.h>
# include <linux/delay.h>
# include <linux/device.h>
# include <linux/dma-mapping.h>
# include <linux/gfp.h>
# include <linux/init.h>
2005-04-16 15:20:36 -07:00
# include <linux/kernel.h>
# include <linux/list.h>
2007-04-23 11:50:56 -07:00
# include <linux/mm.h>
2005-04-16 15:20:36 -07:00
# include <linux/module.h>
# include <linux/moduleparam.h>
2007-04-23 11:50:56 -07:00
# include <linux/sched.h>
2006-08-14 18:56:00 +02:00
# include <linux/slab.h>
# include <linux/spinlock.h>
# include <linux/stat.h>
# include <linux/string.h>
# include <linux/stringify.h>
# include <linux/types.h>
2006-07-23 22:19:00 +02:00
# include <linux/wait.h>
2007-05-05 17:18:12 +02:00
# include <linux/workqueue.h>
2007-10-30 10:35:04 +01:00
# include <linux/scatterlist.h>
2005-04-16 15:20:36 -07:00
# include <asm/byteorder.h>
2006-08-14 18:56:00 +02:00
# include <asm/errno.h>
# include <asm/param.h>
# include <asm/system.h>
# include <asm/types.h>
# ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
# include <asm/io.h> /* for bus_to_virt */
# endif
2005-04-16 15:20:36 -07: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 "csr1212.h"
2006-08-14 18:56:00 +02:00
# include "highlevel.h"
# include "hosts.h"
2005-04-16 15:20:36 -07:00
# include "ieee1394.h"
# include "ieee1394_core.h"
2006-08-14 18:56:00 +02:00
# include "ieee1394_hotplug.h"
2005-04-16 15:20:36 -07:00
# include "ieee1394_transactions.h"
2006-08-14 18:56:00 +02:00
# include "ieee1394_types.h"
# include "nodemgr.h"
2005-04-16 15:20:36 -07:00
# include "sbp2.h"
/*
* Module load parameter definitions
*/
/*
* Change max_speed on module load if you have a bad IEEE - 1394
* controller that has trouble running 2 KB packets at 400 mb .
*
* NOTE : On certain OHCI parts I have seen short packets on async transmit
* ( probably due to PCI latency / throughput issues with the part ) . You can
* bump down the speed if you are running into problems .
*/
2006-11-02 21:16:08 +01:00
static int sbp2_max_speed = IEEE1394_SPEED_MAX ;
module_param_named ( max_speed , sbp2_max_speed , int , 0644 ) ;
2006-11-02 21:16:08 +01:00
MODULE_PARM_DESC ( max_speed , " Force max speed "
" (3 = 800Mb/s, 2 = 400Mb/s, 1 = 200Mb/s, 0 = 100Mb/s) " ) ;
2005-04-16 15:20:36 -07:00
/*
2007-06-17 23:54:52 +02:00
* Set serialize_io to 0 or N to use dynamically appended lists of command ORBs .
* This is and always has been buggy in multiple subtle ways . See above TODOs .
2005-04-16 15:20:36 -07:00
*/
2006-11-02 21:16:08 +01:00
static int sbp2_serialize_io = 1 ;
2007-06-17 23:54:52 +02:00
module_param_named ( serialize_io , sbp2_serialize_io , bool , 0444 ) ;
MODULE_PARM_DESC ( serialize_io , " Serialize requests coming from SCSI drivers "
" (default = Y, faster but buggy = N) " ) ;
2005-04-16 15:20:36 -07:00
/*
2007-12-16 17:31:26 +01:00
* Adjust max_sectors if you ' d like to influence how many sectors each SCSI
* command can transfer at most . Please note that some older SBP - 2 bridge
* chips are broken for transfers greater or equal to 128 KB , therefore
* max_sectors used to be a safe 255 sectors for many years . We now have a
* default of 0 here which means that we let the SCSI stack choose a limit .
*
* The SBP2_WORKAROUND_128K_MAX_TRANS flag , if set either in the workarounds
* module parameter or in the sbp2_workarounds_table [ ] , will override the
* value of max_sectors . We should use sbp2_workarounds_table [ ] to cover any
* bridge chip which becomes known to need the 255 sectors limit .
2005-04-16 15:20:36 -07:00
*/
2007-12-16 17:31:26 +01:00
static int sbp2_max_sectors ;
2006-11-02 21:16:08 +01:00
module_param_named ( max_sectors , sbp2_max_sectors , int , 0444 ) ;
MODULE_PARM_DESC ( max_sectors , " Change max sectors per I/O supported "
2007-12-16 17:31:26 +01:00
" (default = 0 = use SCSI stack's default) " ) ;
2005-04-16 15:20:36 -07:00
/*
* Exclusive login to sbp2 device ? In most cases , the sbp2 driver should
* do an exclusive login , as it ' s generally unsafe to have two hosts
* talking to a single sbp2 device at the same time ( filesystem coherency ,
* etc . ) . If you ' re running an sbp2 device that supports multiple logins ,
* and you ' re either running read - only filesystems or some sort of special
2006-06-12 18:13:11 -04:00
* filesystem supporting multiple hosts , e . g . OpenGFS , Oracle Cluster
* File System , or Lustre , then set exclusive_login to zero .
*
* 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 .
2005-04-16 15:20:36 -07:00
*/
2006-11-02 21:16:08 +01:00
static int sbp2_exclusive_login = 1 ;
2007-06-17 23:54:52 +02:00
module_param_named ( exclusive_login , sbp2_exclusive_login , bool , 0644 ) ;
2006-11-02 21:16:08 +01:00
MODULE_PARM_DESC ( exclusive_login , " Exclusive login to sbp2 device "
2007-06-17 23:54:52 +02:00
" (default = Y, use N for concurrent initiators) " ) ;
2005-04-16 15:20:36 -07:00
/*
2006-05-15 22:04:59 +02:00
* If any of the following workarounds is required for your device to work ,
* please submit the kernel messages logged by sbp2 to the linux1394 - devel
* mailing list .
2005-04-16 15:20:36 -07:00
*
2006-05-15 22:04:59 +02:00
* - 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 .
2006-05-15 22:06:37 +02:00
*
* - 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 .
2006-05-15 22:08:09 +02:00
*
2008-02-03 23:07:44 +01:00
* - delay inquiry
* Wait extra SBP2_INQUIRY_DELAY seconds after login before SCSI inquiry .
*
2006-05-15 22:08:09 +02: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 .
2005-04-16 15:20:36 -07:00
*/
2006-05-15 22:04:59 +02:00
static int sbp2_default_workarounds ;
module_param_named ( workarounds , sbp2_default_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 )
2006-05-15 22:06:37 +02:00
" , fix capacity = " __stringify ( SBP2_WORKAROUND_FIX_CAPACITY )
2008-02-03 23:07:44 +01:00
" , delay inquiry = " __stringify ( SBP2_WORKAROUND_DELAY_INQUIRY )
2006-05-15 22:08:09 +02:00
" , override internal blacklist = " __stringify ( SBP2_WORKAROUND_OVERRIDE )
2006-05-15 22:04:59 +02:00
" , or a combination) " ) ;
2007-05-27 13:17:15 +02:00
/*
* This influences the format of the sysfs attribute
* / sys / bus / scsi / devices / . . . / ieee1394_id .
*
* The default format is like in older kernels : % 016L x : % d : % d
* It contains the target ' s EUI - 64 , a number given to the logical unit by
* the ieee1394 driver ' s nodemgr ( starting at 0 ) , and the LUN .
*
* The long format is : % 016L x : % 06 x : % 04 x
* It contains the target ' s EUI - 64 , the unit directory ' s directory_ID as per
* IEEE 1212 clause 7.7 .19 , and the LUN . This format comes closest to the
* format of SBP ( - 3 ) target port and logical unit identifier as per SAM ( SCSI
* Architecture Model ) rev .2 to 4 annex A . Therefore and because it is
* independent of the implementation of the ieee1394 nodemgr , the longer format
* is recommended for future use .
*/
static int sbp2_long_sysfs_ieee1394_id ;
module_param_named ( long_ieee1394_id , sbp2_long_sysfs_ieee1394_id , bool , 0644 ) ;
MODULE_PARM_DESC ( long_ieee1394_id , " 8+3+2 bytes format of ieee1394_id in sysfs "
" (default = backwards-compatible = N, SAM-conforming = Y) " ) ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
# define SBP2_INFO(fmt, args...) HPSB_INFO("sbp2: "fmt, ## args)
# define SBP2_ERR(fmt, args...) HPSB_ERR("sbp2: "fmt, ## args)
2005-04-16 15:20:36 -07:00
/*
* Globals
*/
2006-11-02 21:16:08 +01:00
static void sbp2scsi_complete_all_commands ( struct sbp2_lu * , u32 ) ;
static void sbp2scsi_complete_command ( struct sbp2_lu * , u32 , struct scsi_cmnd * ,
2006-11-02 21:16:08 +01:00
void ( * ) ( struct scsi_cmnd * ) ) ;
2006-11-02 21:16:08 +01:00
static struct sbp2_lu * sbp2_alloc_device ( struct unit_directory * ) ;
static int sbp2_start_device ( struct sbp2_lu * ) ;
static void sbp2_remove_device ( struct sbp2_lu * ) ;
static int sbp2_login_device ( struct sbp2_lu * ) ;
static int sbp2_reconnect_device ( struct sbp2_lu * ) ;
static int sbp2_logout_device ( struct sbp2_lu * ) ;
2006-11-02 21:16:08 +01:00
static void sbp2_host_reset ( struct hpsb_host * ) ;
static int sbp2_handle_status_write ( struct hpsb_host * , int , int , quadlet_t * ,
u64 , size_t , u16 ) ;
2006-11-02 21:16:08 +01:00
static int sbp2_agent_reset ( struct sbp2_lu * , int ) ;
static void sbp2_parse_unit_directory ( struct sbp2_lu * ,
2006-11-02 21:16:08 +01:00
struct unit_directory * ) ;
2006-11-02 21:16:08 +01:00
static int sbp2_set_busy_timeout ( struct sbp2_lu * ) ;
static int sbp2_max_speed_and_size ( struct sbp2_lu * ) ;
2005-04-16 15:20:36 -07:00
static const u8 sbp2_speedto_max_payload [ ] = { 0x7 , 0x8 , 0x9 , 0xA , 0xB , 0xC } ;
2007-08-11 11:52:08 +02:00
static DEFINE_RWLOCK ( sbp2_hi_logical_units_lock ) ;
2005-04-16 15:20:36 -07:00
static struct hpsb_highlevel sbp2_highlevel = {
2006-11-02 21:16:08 +01:00
. name = SBP2_DEVICE_NAME ,
. host_reset = sbp2_host_reset ,
2005-04-16 15:20:36 -07:00
} ;
static struct hpsb_address_ops sbp2_ops = {
2006-11-02 21:16:08 +01:00
. write = sbp2_handle_status_write
2005-04-16 15:20:36 -07:00
} ;
# ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
2006-11-02 21:16:08 +01:00
static int sbp2_handle_physdma_write ( struct hpsb_host * , int , int , quadlet_t * ,
u64 , size_t , u16 ) ;
static int sbp2_handle_physdma_read ( struct hpsb_host * , int , quadlet_t * , u64 ,
size_t , u16 ) ;
2005-04-16 15:20:36 -07:00
static struct hpsb_address_ops sbp2_physdma_ops = {
2006-11-02 21:16:08 +01:00
. read = sbp2_handle_physdma_read ,
. write = sbp2_handle_physdma_write ,
2005-04-16 15:20:36 -07:00
} ;
# endif
2006-11-02 21:16:08 +01:00
/*
* Interface to driver core and IEEE 1394 core
*/
static struct ieee1394_device_id sbp2_id_table [ ] = {
{
. match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION ,
. specifier_id = SBP2_UNIT_SPEC_ID_ENTRY & 0xffffff ,
. version = SBP2_SW_VERSION_ENTRY & 0xffffff } ,
{ }
} ;
MODULE_DEVICE_TABLE ( ieee1394 , sbp2_id_table ) ;
static int sbp2_probe ( struct device * ) ;
static int sbp2_remove ( struct device * ) ;
static int sbp2_update ( struct unit_directory * ) ;
2005-04-16 15:20:36 -07:00
static struct hpsb_protocol_driver sbp2_driver = {
2006-11-23 13:59:48 -05:00
. name = SBP2_DEVICE_NAME ,
2005-04-16 15:20:36 -07:00
. id_table = sbp2_id_table ,
. update = sbp2_update ,
. driver = {
. probe = sbp2_probe ,
. remove = sbp2_remove ,
} ,
} ;
2006-11-02 21:16:08 +01:00
/*
* Interface to SCSI core
*/
static int sbp2scsi_queuecommand ( struct scsi_cmnd * ,
void ( * ) ( struct scsi_cmnd * ) ) ;
static int sbp2scsi_abort ( struct scsi_cmnd * ) ;
static int sbp2scsi_reset ( struct scsi_cmnd * ) ;
static int sbp2scsi_slave_alloc ( struct scsi_device * ) ;
static int sbp2scsi_slave_configure ( struct scsi_device * ) ;
static void sbp2scsi_slave_destroy ( struct scsi_device * ) ;
static ssize_t sbp2_sysfs_ieee1394_id_show ( struct device * ,
struct device_attribute * , char * ) ;
static DEVICE_ATTR ( ieee1394_id , S_IRUGO , sbp2_sysfs_ieee1394_id_show , NULL ) ;
static struct device_attribute * sbp2_sysfs_sdev_attrs [ ] = {
& dev_attr_ieee1394_id ,
NULL
} ;
2006-11-02 21:16:08 +01:00
static struct scsi_host_template sbp2_shost_template = {
2006-11-02 21:16:08 +01:00
. module = THIS_MODULE ,
. name = " SBP-2 IEEE-1394 " ,
. proc_name = SBP2_DEVICE_NAME ,
. queuecommand = sbp2scsi_queuecommand ,
. eh_abort_handler = sbp2scsi_abort ,
. eh_device_reset_handler = sbp2scsi_reset ,
. slave_alloc = sbp2scsi_slave_alloc ,
. slave_configure = sbp2scsi_slave_configure ,
. slave_destroy = sbp2scsi_slave_destroy ,
. this_id = - 1 ,
. sg_tablesize = SG_ALL ,
. use_clustering = ENABLE_CLUSTERING ,
. cmd_per_lun = SBP2_MAX_CMDS ,
. can_queue = SBP2_MAX_CMDS ,
. sdev_attrs = sbp2_sysfs_sdev_attrs ,
} ;
2006-12-30 15:37:09 +01:00
/* for match-all entries in sbp2_workarounds_table */
# define SBP2_ROM_VALUE_WILDCARD 0x1000000
2006-11-02 21:16:08 +01:00
2006-02-14 22:04:19 -05:00
/*
2006-05-15 22:04:59 +02:00
* 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 .
2006-02-14 22:04:19 -05:00
*/
2006-05-15 22:04:59 +02:00
static const struct {
u32 firmware_revision ;
2006-05-15 22:06:37 +02:00
u32 model_id ;
2006-05-15 22:04:59 +02:00
unsigned workarounds ;
} sbp2_workarounds_table [ ] = {
2006-06-12 18:10:18 -04:00
/* DViCO Momobay CX-1 with TSB42AA9 bridge */ {
2006-05-15 22:04:59 +02:00
. firmware_revision = 0x002800 ,
2006-06-12 18:10:18 -04:00
. model_id = 0x001010 ,
2006-05-15 22:04:59 +02:00
. workarounds = SBP2_WORKAROUND_INQUIRY_36 |
SBP2_WORKAROUND_MODE_SENSE_8 ,
} ,
2008-02-03 23:07:44 +01:00
/* DViCO Momobay FX-3A with TSB42AA9A bridge */ {
. firmware_revision = 0x002800 ,
. model_id = 0x000000 ,
. workarounds = SBP2_WORKAROUND_DELAY_INQUIRY ,
} ,
2006-05-15 22:04:59 +02:00
/* Initio bridges, actually only needed for some older ones */ {
. firmware_revision = 0x000200 ,
2006-12-30 15:37:09 +01:00
. model_id = SBP2_ROM_VALUE_WILDCARD ,
2006-05-15 22:04:59 +02:00
. workarounds = SBP2_WORKAROUND_INQUIRY_36 ,
} ,
/* Symbios bridge */ {
. firmware_revision = 0xa0b800 ,
2006-12-30 15:37:09 +01:00
. model_id = SBP2_ROM_VALUE_WILDCARD ,
2006-05-15 22:04:59 +02:00
. workarounds = SBP2_WORKAROUND_128K_MAX_TRANS ,
2006-05-15 22:06:37 +02:00
} ,
2008-03-11 22:32:52 +01:00
/* Datafab MD2-FW2 with Symbios/LSILogic SYM13FW500 bridge */ {
. firmware_revision = 0x002600 ,
. model_id = SBP2_ROM_VALUE_WILDCARD ,
. workarounds = SBP2_WORKAROUND_128K_MAX_TRANS ,
} ,
2006-05-15 22:06:37 +02:00
/* iPod 4th generation */ {
. firmware_revision = 0x0a2700 ,
. model_id = 0x000021 ,
. workarounds = SBP2_WORKAROUND_FIX_CAPACITY ,
} ,
/* iPod mini */ {
. firmware_revision = 0x0a2700 ,
. model_id = 0x000023 ,
. workarounds = SBP2_WORKAROUND_FIX_CAPACITY ,
} ,
/* iPod Photo */ {
. firmware_revision = 0x0a2700 ,
. model_id = 0x00007e ,
. workarounds = SBP2_WORKAROUND_FIX_CAPACITY ,
2006-05-15 22:04:59 +02:00
}
2005-04-16 15:20:36 -07:00
} ;
/**************************************
* General utility functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifndef __BIG_ENDIAN
/*
* Converts a buffer from be32 to cpu byte ordering . Length is in bytes .
*/
2006-07-03 12:02:28 -04:00
static inline void sbp2util_be32_to_cpu_buffer ( void * buffer , int length )
2005-04-16 15:20:36 -07:00
{
u32 * temp = buffer ;
for ( length = ( length > > 2 ) ; length - - ; )
temp [ length ] = be32_to_cpu ( temp [ length ] ) ;
}
/*
* Converts a buffer from cpu to be32 byte ordering . Length is in bytes .
*/
2006-07-03 12:02:28 -04:00
static inline void sbp2util_cpu_to_be32_buffer ( void * buffer , int length )
2005-04-16 15:20:36 -07:00
{
u32 * temp = buffer ;
for ( length = ( length > > 2 ) ; length - - ; )
temp [ length ] = cpu_to_be32 ( temp [ length ] ) ;
}
# else /* BIG_ENDIAN */
/* Why waste the cpu cycles? */
2006-08-02 18:44:00 +02:00
# define sbp2util_be32_to_cpu_buffer(x,y) do {} while (0)
# define sbp2util_cpu_to_be32_buffer(x,y) do {} while (0)
2005-04-16 15:20:36 -07:00
# endif
2006-11-02 21:16:08 +01:00
static DECLARE_WAIT_QUEUE_HEAD ( sbp2_access_wq ) ;
2006-07-23 22:19:00 +02:00
2005-04-16 15:20:36 -07:00
/*
2006-07-23 22:19:00 +02:00
* Waits for completion of an SBP - 2 access request .
* Returns nonzero if timed out or prematurely interrupted .
2005-04-16 15:20:36 -07:00
*/
2006-11-02 21:16:08 +01:00
static int sbp2util_access_timeout ( struct sbp2_lu * lu , int timeout )
2005-04-16 15:20:36 -07:00
{
2006-11-02 21:16:08 +01:00
long leftover ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
leftover = wait_event_interruptible_timeout (
2006-11-02 21:16:08 +01:00
sbp2_access_wq , lu - > access_complete , timeout ) ;
lu - > access_complete = 0 ;
2006-07-23 22:19:00 +02:00
return leftover < = 0 ;
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
static void sbp2_free_packet ( void * packet )
2005-04-16 15:20:36 -07:00
{
hpsb_free_tlabel ( packet ) ;
hpsb_free_packet ( packet ) ;
}
2006-11-02 21:16:08 +01:00
/*
* This is much like hpsb_node_write ( ) , except it ignores the response
* subaction and returns immediately . Can be used from atomic context .
2005-04-16 15:20:36 -07:00
*/
static int sbp2util_node_write_no_wait ( struct node_entry * ne , u64 addr ,
2006-11-02 21:16:08 +01:00
quadlet_t * buf , size_t len )
2005-04-16 15:20:36 -07:00
{
struct hpsb_packet * packet ;
2006-11-02 21:16:08 +01:00
packet = hpsb_make_writepacket ( ne - > host , ne - > nodeid , addr , buf , len ) ;
2005-11-07 06:31:39 -05:00
if ( ! packet )
return - ENOMEM ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
hpsb_set_packet_complete_task ( packet , sbp2_free_packet , packet ) ;
2005-04-16 15:20:36 -07:00
hpsb_node_fill_packet ( ne , packet ) ;
2005-11-07 06:31:39 -05:00
if ( hpsb_send_packet ( packet ) < 0 ) {
2005-04-16 15:20:36 -07:00
sbp2_free_packet ( packet ) ;
return - EIO ;
}
return 0 ;
}
2006-11-02 21:16:08 +01:00
static void sbp2util_notify_fetch_agent ( struct sbp2_lu * lu , u64 offset ,
quadlet_t * data , size_t len )
2006-08-14 18:43:00 +02:00
{
2006-11-02 21:16:08 +01:00
/* There is a small window after a bus reset within which the node
* entry ' s generation is current but the reconnect wasn ' t completed . */
if ( unlikely ( atomic_read ( & lu - > state ) = = SBP2LU_STATE_IN_RESET ) )
2006-08-14 18:43:00 +02:00
return ;
2006-11-02 21:16:08 +01:00
if ( hpsb_node_write ( lu - > ne , lu - > command_block_agent_addr + offset ,
2006-08-14 18:43:00 +02:00
data , len ) )
SBP2_ERR ( " sbp2util_notify_fetch_agent failed. " ) ;
2006-11-02 21:16:08 +01:00
/* Now accept new SCSI commands, unless a bus reset happended during
* hpsb_node_write . */
if ( likely ( atomic_read ( & lu - > state ) ! = SBP2LU_STATE_IN_RESET ) )
scsi_unblock_requests ( lu - > shost ) ;
2006-08-14 18:43:00 +02:00
}
2006-11-22 14:57:56 +00:00
static void sbp2util_write_orb_pointer ( struct work_struct * work )
2006-08-14 18:43:00 +02:00
{
2006-12-07 23:23:25 +01:00
struct sbp2_lu * lu = container_of ( work , struct sbp2_lu , protocol_work ) ;
2006-08-14 18:43:00 +02:00
quadlet_t data [ 2 ] ;
2006-12-07 23:23:25 +01:00
data [ 0 ] = ORB_SET_NODE_ID ( lu - > hi - > host - > node_id ) ;
data [ 1 ] = lu - > last_orb_dma ;
2006-08-14 18:43:00 +02:00
sbp2util_cpu_to_be32_buffer ( data , 8 ) ;
2006-12-07 23:23:25 +01:00
sbp2util_notify_fetch_agent ( lu , SBP2_ORB_POINTER_OFFSET , data , 8 ) ;
2006-08-14 18:43:00 +02:00
}
2006-11-22 14:57:56 +00:00
static void sbp2util_write_doorbell ( struct work_struct * work )
2006-08-14 18:43:00 +02:00
{
2006-12-07 23:23:25 +01:00
struct sbp2_lu * lu = container_of ( work , struct sbp2_lu , protocol_work ) ;
sbp2util_notify_fetch_agent ( lu , SBP2_DOORBELL_OFFSET , NULL , 4 ) ;
2006-08-14 18:43:00 +02:00
}
2006-11-02 21:16:08 +01:00
static int sbp2util_create_command_orb_pool ( struct sbp2_lu * lu )
2005-04-16 15:20:36 -07:00
{
2006-11-02 21:16:08 +01:00
struct sbp2_fwhost_info * hi = lu - > hi ;
struct sbp2_command_info * cmd ;
2007-02-04 20:57:38 +01:00
int i , orbs = sbp2_serialize_io ? 2 : SBP2_MAX_CMDS ;
2005-04-16 15:20:36 -07:00
for ( i = 0 ; i < orbs ; i + + ) {
2007-02-04 20:57:38 +01:00
cmd = kzalloc ( sizeof ( * cmd ) , GFP_KERNEL ) ;
if ( ! cmd )
2005-11-07 06:31:39 -05:00
return - ENOMEM ;
2006-12-29 23:47:04 +01:00
cmd - > command_orb_dma = dma_map_single ( hi - > host - > device . parent ,
2006-11-02 21:16:08 +01:00
& cmd - > command_orb ,
sizeof ( struct sbp2_command_orb ) ,
2006-11-22 21:44:34 +01:00
DMA_TO_DEVICE ) ;
2006-12-29 23:47:04 +01:00
cmd - > sge_dma = dma_map_single ( hi - > host - > device . parent ,
2006-11-02 21:16:08 +01:00
& cmd - > scatter_gather_element ,
sizeof ( cmd - > scatter_gather_element ) ,
2007-02-04 20:54:57 +01:00
DMA_TO_DEVICE ) ;
2006-11-02 21:16:08 +01:00
INIT_LIST_HEAD ( & cmd - > list ) ;
list_add_tail ( & cmd - > list , & lu - > cmd_orb_completed ) ;
2005-04-16 15:20:36 -07:00
}
return 0 ;
}
2007-08-11 11:51:16 +02:00
static void sbp2util_remove_command_orb_pool ( struct sbp2_lu * lu ,
struct hpsb_host * host )
2005-04-16 15:20:36 -07:00
{
struct list_head * lh , * next ;
2006-11-02 21:16:08 +01:00
struct sbp2_command_info * cmd ;
2005-04-16 15:20:36 -07:00
unsigned long flags ;
2006-11-02 21:16:08 +01:00
spin_lock_irqsave ( & lu - > cmd_orb_lock , flags ) ;
if ( ! list_empty ( & lu - > cmd_orb_completed ) )
list_for_each_safe ( lh , next , & lu - > cmd_orb_completed ) {
cmd = list_entry ( lh , struct sbp2_command_info , list ) ;
2006-12-29 23:47:04 +01:00
dma_unmap_single ( host - > device . parent ,
cmd - > command_orb_dma ,
2005-04-16 15:20:36 -07:00
sizeof ( struct sbp2_command_orb ) ,
2006-11-22 21:44:34 +01:00
DMA_TO_DEVICE ) ;
2006-12-29 23:47:04 +01:00
dma_unmap_single ( host - > device . parent , cmd - > sge_dma ,
2006-11-02 21:16:08 +01:00
sizeof ( cmd - > scatter_gather_element ) ,
2007-02-04 20:54:57 +01:00
DMA_TO_DEVICE ) ;
2006-11-02 21:16:08 +01:00
kfree ( cmd ) ;
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
spin_unlock_irqrestore ( & lu - > cmd_orb_lock , flags ) ;
2005-04-16 15:20:36 -07:00
return ;
}
/*
2006-11-02 21:16:08 +01:00
* Finds the sbp2_command for a given outstanding command ORB .
* Only looks at the in - use list .
2005-04-16 15:20:36 -07:00
*/
static struct sbp2_command_info * sbp2util_find_command_for_orb (
2006-11-02 21:16:08 +01:00
struct sbp2_lu * lu , dma_addr_t orb )
2005-04-16 15:20:36 -07:00
{
2006-11-02 21:16:08 +01:00
struct sbp2_command_info * cmd ;
2005-04-16 15:20:36 -07:00
unsigned long flags ;
2006-11-02 21:16:08 +01:00
spin_lock_irqsave ( & lu - > cmd_orb_lock , flags ) ;
if ( ! list_empty ( & lu - > cmd_orb_inuse ) )
list_for_each_entry ( cmd , & lu - > cmd_orb_inuse , list )
if ( cmd - > command_orb_dma = = orb ) {
spin_unlock_irqrestore (
& lu - > cmd_orb_lock , flags ) ;
return cmd ;
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
spin_unlock_irqrestore ( & lu - > cmd_orb_lock , flags ) ;
2005-11-07 06:31:39 -05:00
return NULL ;
2005-04-16 15:20:36 -07:00
}
/*
2006-11-02 21:16:08 +01:00
* Finds the sbp2_command for a given outstanding SCpnt .
* Only looks at the in - use list .
2006-11-02 21:16:08 +01:00
* Must be called with lu - > cmd_orb_lock held .
2005-04-16 15:20:36 -07:00
*/
2006-04-01 21:11:41 +02:00
static struct sbp2_command_info * sbp2util_find_command_for_SCpnt (
2006-11-02 21:16:08 +01:00
struct sbp2_lu * lu , void * SCpnt )
2005-04-16 15:20:36 -07:00
{
2006-11-02 21:16:08 +01:00
struct sbp2_command_info * cmd ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
if ( ! list_empty ( & lu - > cmd_orb_inuse ) )
list_for_each_entry ( cmd , & lu - > cmd_orb_inuse , list )
if ( cmd - > Current_SCpnt = = SCpnt )
return cmd ;
2005-11-07 06:31:39 -05:00
return NULL ;
2005-04-16 15:20:36 -07:00
}
static struct sbp2_command_info * sbp2util_allocate_command_orb (
2006-11-02 21:16:08 +01:00
struct sbp2_lu * lu ,
struct scsi_cmnd * Current_SCpnt ,
void ( * Current_done ) ( struct scsi_cmnd * ) )
2005-04-16 15:20:36 -07:00
{
struct list_head * lh ;
2006-11-02 21:16:08 +01:00
struct sbp2_command_info * cmd = NULL ;
2005-04-16 15:20:36 -07:00
unsigned long flags ;
2006-11-02 21:16:08 +01:00
spin_lock_irqsave ( & lu - > cmd_orb_lock , flags ) ;
if ( ! list_empty ( & lu - > cmd_orb_completed ) ) {
lh = lu - > cmd_orb_completed . next ;
2005-04-16 15:20:36 -07:00
list_del ( lh ) ;
2006-11-02 21:16:08 +01:00
cmd = list_entry ( lh , struct sbp2_command_info , list ) ;
cmd - > Current_done = Current_done ;
cmd - > Current_SCpnt = Current_SCpnt ;
list_add_tail ( & cmd - > list , & lu - > cmd_orb_inuse ) ;
} else
2008-03-05 18:24:54 -08:00
SBP2_ERR ( " %s: no orbs available " , __func__ ) ;
2006-11-02 21:16:08 +01:00
spin_unlock_irqrestore ( & lu - > cmd_orb_lock , flags ) ;
return cmd ;
2005-04-16 15:20:36 -07:00
}
2006-11-04 09:55:33 +01:00
/*
* Unmaps the DMAs of a command and moves the command to the completed ORB list .
* Must be called with lu - > cmd_orb_lock held .
*/
static void sbp2util_mark_command_completed ( struct sbp2_lu * lu ,
struct sbp2_command_info * cmd )
2005-04-16 15:20:36 -07:00
{
2006-11-04 09:55:33 +01:00
struct hpsb_host * host = lu - > ud - > ne - > host ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
if ( cmd - > cmd_dma ) {
if ( cmd - > dma_type = = CMD_DMA_SINGLE )
2006-12-29 23:47:04 +01:00
dma_unmap_single ( host - > device . parent , cmd - > cmd_dma ,
2006-11-02 21:16:08 +01:00
cmd - > dma_size , cmd - > dma_dir ) ;
else if ( cmd - > dma_type = = CMD_DMA_PAGE )
2006-12-29 23:47:04 +01:00
dma_unmap_page ( host - > device . parent , cmd - > cmd_dma ,
2006-11-02 21:16:08 +01:00
cmd - > dma_size , cmd - > dma_dir ) ;
2006-11-02 21:16:08 +01:00
/* XXX: Check for CMD_DMA_NONE bug */
2006-11-02 21:16:08 +01:00
cmd - > dma_type = CMD_DMA_NONE ;
cmd - > cmd_dma = 0 ;
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
if ( cmd - > sge_buffer ) {
2006-12-29 23:47:04 +01:00
dma_unmap_sg ( host - > device . parent , cmd - > sge_buffer ,
2006-11-02 21:16:08 +01:00
cmd - > dma_size , cmd - > dma_dir ) ;
cmd - > sge_buffer = NULL ;
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
list_move_tail ( & cmd - > list , & lu - > cmd_orb_completed ) ;
2005-04-16 15:20:36 -07:00
}
2005-09-30 11:59:06 -07:00
/*
2006-11-02 21:16:08 +01:00
* Is lu valid ? Is the 1394 node still present ?
2005-09-30 11:59:06 -07:00
*/
2006-11-02 21:16:08 +01:00
static inline int sbp2util_node_is_available ( struct sbp2_lu * lu )
2005-09-30 11:59:06 -07:00
{
2006-11-02 21:16:08 +01:00
return lu & & lu - > ne & & ! lu - > ne - > in_limbo ;
2005-09-30 11:59:06 -07:00
}
2005-04-16 15:20:36 -07:00
/*********************************************
* IEEE - 1394 core driver stack related section
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int sbp2_probe ( struct device * dev )
{
struct unit_directory * ud ;
2006-11-02 21:16:08 +01:00
struct sbp2_lu * lu ;
2005-04-16 15:20:36 -07:00
ud = container_of ( dev , struct unit_directory , device ) ;
/* Don't probe UD's that have the LUN flag. We'll probe the LUN(s)
* instead . */
if ( ud - > flags & UNIT_DIRECTORY_HAS_LUN_DIRECTORY )
return - ENODEV ;
2006-11-02 21:16:08 +01:00
lu = sbp2_alloc_device ( ud ) ;
if ( ! lu )
2005-11-07 06:31:39 -05:00
return - ENOMEM ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
sbp2_parse_unit_directory ( lu , ud ) ;
return sbp2_start_device ( lu ) ;
2005-04-16 15:20:36 -07:00
}
static int sbp2_remove ( struct device * dev )
{
struct unit_directory * ud ;
2006-11-02 21:16:08 +01:00
struct sbp2_lu * lu ;
2005-09-30 11:59:06 -07:00
struct scsi_device * sdev ;
2005-04-16 15:20:36 -07:00
ud = container_of ( dev , struct unit_directory , device ) ;
2006-11-02 21:16:08 +01:00
lu = ud - > device . driver_data ;
if ( ! lu )
2005-09-30 11:59:06 -07:00
return 0 ;
2006-11-02 21:16:08 +01:00
if ( lu - > shost ) {
2006-01-31 00:13:06 -05:00
/* Get rid of enqueued commands if there is no chance to
* send them . */
2006-11-02 21:16:08 +01:00
if ( ! sbp2util_node_is_available ( lu ) )
sbp2scsi_complete_all_commands ( lu , DID_NO_CONNECT ) ;
2006-11-02 21:16:08 +01:00
/* scsi_remove_device() may trigger shutdown functions of SCSI
2006-01-31 00:13:06 -05:00
* highlevel drivers which would deadlock if blocked . */
2006-11-02 21:16:08 +01:00
atomic_set ( & lu - > state , SBP2LU_STATE_IN_SHUTDOWN ) ;
scsi_unblock_requests ( lu - > shost ) ;
2006-01-31 00:13:06 -05:00
}
2006-11-02 21:16:08 +01:00
sdev = lu - > sdev ;
2005-09-30 11:59:06 -07:00
if ( sdev ) {
2006-11-02 21:16:08 +01:00
lu - > sdev = NULL ;
2005-09-30 11:59:06 -07:00
scsi_remove_device ( sdev ) ;
}
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
sbp2_logout_device ( lu ) ;
sbp2_remove_device ( lu ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
static int sbp2_update ( struct unit_directory * ud )
{
2006-11-02 21:16:08 +01:00
struct sbp2_lu * lu = ud - > device . driver_data ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
if ( sbp2_reconnect_device ( lu ) ) {
2006-11-02 21:16:08 +01:00
/* Reconnect has failed. Perhaps we didn't reconnect fast
* enough . Try a regular login , but first log out just in
* case of any weirdness . */
2006-11-02 21:16:08 +01:00
sbp2_logout_device ( lu ) ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
if ( sbp2_login_device ( lu ) ) {
2005-04-16 15:20:36 -07:00
/* Login failed too, just fail, and the backend
* will call our sbp2_remove for us */
SBP2_ERR ( " Failed to reconnect to sbp2 device! " ) ;
return - EBUSY ;
}
}
2006-11-02 21:16:08 +01:00
sbp2_set_busy_timeout ( lu ) ;
sbp2_agent_reset ( lu , 1 ) ;
sbp2_max_speed_and_size ( lu ) ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
/* Complete any pending commands with busy (so they get retried)
* and remove them from our queue . */
2006-11-02 21:16:08 +01:00
sbp2scsi_complete_all_commands ( lu , DID_BUS_BUSY ) ;
2005-04-16 15:20:36 -07:00
2006-08-14 18:46:00 +02:00
/* Accept new commands unless there was another bus reset in the
* meantime . */
2006-11-02 21:16:08 +01:00
if ( hpsb_node_entry_valid ( lu - > ne ) ) {
atomic_set ( & lu - > state , SBP2LU_STATE_RUNNING ) ;
scsi_unblock_requests ( lu - > shost ) ;
2006-08-14 18:46:00 +02:00
}
2005-04-16 15:20:36 -07:00
return 0 ;
}
2006-11-02 21:16:08 +01:00
static struct sbp2_lu * sbp2_alloc_device ( struct unit_directory * ud )
2005-04-16 15:20:36 -07:00
{
2006-11-02 21:16:08 +01:00
struct sbp2_fwhost_info * hi ;
2006-11-02 21:16:08 +01:00
struct Scsi_Host * shost = NULL ;
struct sbp2_lu * lu = NULL ;
2007-08-11 11:52:08 +02:00
unsigned long flags ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
lu = kzalloc ( sizeof ( * lu ) , GFP_KERNEL ) ;
if ( ! lu ) {
SBP2_ERR ( " failed to create lu " ) ;
2005-04-16 15:20:36 -07:00
goto failed_alloc ;
}
2006-11-02 21:16:08 +01:00
lu - > ne = ud - > ne ;
lu - > ud = ud ;
lu - > speed_code = IEEE1394_SPEED_100 ;
lu - > max_payload_size = sbp2_speedto_max_payload [ IEEE1394_SPEED_100 ] ;
lu - > status_fifo_addr = CSR1212_INVALID_ADDR_SPACE ;
INIT_LIST_HEAD ( & lu - > cmd_orb_inuse ) ;
INIT_LIST_HEAD ( & lu - > cmd_orb_completed ) ;
INIT_LIST_HEAD ( & lu - > lu_list ) ;
spin_lock_init ( & lu - > cmd_orb_lock ) ;
atomic_set ( & lu - > state , SBP2LU_STATE_RUNNING ) ;
INIT_WORK ( & lu - > protocol_work , NULL ) ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
ud - > device . driver_data = lu ;
2005-04-16 15:20:36 -07:00
hi = hpsb_get_hostinfo ( & sbp2_highlevel , ud - > ne - > host ) ;
if ( ! hi ) {
2006-11-02 21:16:08 +01:00
hi = hpsb_create_hostinfo ( & sbp2_highlevel , ud - > ne - > host ,
sizeof ( * hi ) ) ;
2005-04-16 15:20:36 -07:00
if ( ! hi ) {
SBP2_ERR ( " failed to allocate hostinfo " ) ;
goto failed_alloc ;
}
hi - > host = ud - > ne - > host ;
2006-11-02 21:16:08 +01:00
INIT_LIST_HEAD ( & hi - > logical_units ) ;
2005-04-16 15:20:36 -07:00
# ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
/* Handle data movement if physical dma is not
2006-03-28 19:59:42 -05:00
* enabled or not supported on host controller */
if ( ! hpsb_register_addrspace ( & sbp2_highlevel , ud - > ne - > host ,
& sbp2_physdma_ops ,
0x0ULL , 0xfffffffcULL ) ) {
SBP2_ERR ( " failed to register lower 4GB address range " ) ;
goto failed_alloc ;
}
2005-04-16 15:20:36 -07:00
# endif
}
2006-03-28 19:54:52 -05:00
/* Prevent unloading of the 1394 host */
if ( ! try_module_get ( hi - > host - > driver - > owner ) ) {
SBP2_ERR ( " failed to get a reference on 1394 host driver " ) ;
goto failed_alloc ;
}
2006-11-02 21:16:08 +01:00
lu - > hi = hi ;
2005-04-16 15:20:36 -07:00
2007-08-11 11:52:08 +02:00
write_lock_irqsave ( & sbp2_hi_logical_units_lock , flags ) ;
2006-11-02 21:16:08 +01:00
list_add_tail ( & lu - > lu_list , & hi - > logical_units ) ;
2007-08-11 11:52:08 +02:00
write_unlock_irqrestore ( & sbp2_hi_logical_units_lock , flags ) ;
2005-04-16 15:20:36 -07:00
2006-01-31 00:13:33 -05:00
/* Register the status FIFO address range. We could use the same FIFO
* for targets at different nodes . However we need different FIFOs per
2006-05-15 22:09:46 +02:00
* target in order to support multi - unit devices .
* The FIFO is located out of the local host controller ' s physical range
* but , if possible , within the posted write area . Status writes will
* then be performed as unified transactions . This slightly reduces
* bandwidth usage , and some Prolific based devices seem to require it .
*/
2006-11-02 21:16:08 +01:00
lu - > status_fifo_addr = hpsb_allocate_and_register_addrspace (
2006-01-31 00:13:33 -05:00
& sbp2_highlevel , ud - > ne - > host , & sbp2_ops ,
sizeof ( struct sbp2_status_block ) , sizeof ( quadlet_t ) ,
2006-06-12 18:13:49 -04:00
ud - > ne - > host - > low_addr_space , CSR1212_ALL_SPACE_END ) ;
2006-11-02 21:16:08 +01:00
if ( lu - > status_fifo_addr = = CSR1212_INVALID_ADDR_SPACE ) {
2006-01-31 00:13:33 -05:00
SBP2_ERR ( " failed to allocate status FIFO address range " ) ;
goto failed_alloc ;
}
2006-11-02 21:16:08 +01:00
shost = scsi_host_alloc ( & sbp2_shost_template , sizeof ( unsigned long ) ) ;
if ( ! shost ) {
2005-04-16 15:20:36 -07:00
SBP2_ERR ( " failed to register scsi host " ) ;
goto failed_alloc ;
}
2006-11-02 21:16:08 +01:00
shost - > hostdata [ 0 ] = ( unsigned long ) lu ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
if ( ! scsi_add_host ( shost , & ud - > device ) ) {
lu - > shost = shost ;
return lu ;
2005-04-16 15:20:36 -07:00
}
SBP2_ERR ( " failed to add scsi host " ) ;
2006-11-02 21:16:08 +01:00
scsi_host_put ( shost ) ;
2005-04-16 15:20:36 -07:00
failed_alloc :
2006-11-02 21:16:08 +01:00
sbp2_remove_device ( lu ) ;
2005-04-16 15:20:36 -07:00
return NULL ;
}
static void sbp2_host_reset ( struct hpsb_host * host )
{
2006-11-02 21:16:08 +01:00
struct sbp2_fwhost_info * hi ;
2006-11-02 21:16:08 +01:00
struct sbp2_lu * lu ;
2007-08-11 11:52:08 +02:00
unsigned long flags ;
2005-04-16 15:20:36 -07:00
hi = hpsb_get_hostinfo ( & sbp2_highlevel , host ) ;
2006-08-14 18:59:00 +02:00
if ( ! hi )
return ;
2007-08-11 11:52:08 +02:00
read_lock_irqsave ( & sbp2_hi_logical_units_lock , flags ) ;
2006-11-02 21:16:08 +01:00
list_for_each_entry ( lu , & hi - > logical_units , lu_list )
if ( likely ( atomic_read ( & lu - > state ) ! =
2006-08-14 18:59:00 +02:00
SBP2LU_STATE_IN_SHUTDOWN ) ) {
2006-11-02 21:16:08 +01:00
atomic_set ( & lu - > state , SBP2LU_STATE_IN_RESET ) ;
scsi_block_requests ( lu - > shost ) ;
2006-08-14 18:43:00 +02:00
}
2007-08-11 11:52:08 +02:00
read_unlock_irqrestore ( & sbp2_hi_logical_units_lock , flags ) ;
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
static int sbp2_start_device ( struct sbp2_lu * lu )
2005-04-16 15:20:36 -07:00
{
2006-11-02 21:16:08 +01:00
struct sbp2_fwhost_info * hi = lu - > hi ;
2005-09-10 12:44:09 -05:00
int error ;
2005-04-16 15:20:36 -07:00
2006-12-29 23:47:04 +01:00
lu - > login_response = dma_alloc_coherent ( hi - > host - > device . parent ,
2005-11-07 06:31:39 -05:00
sizeof ( struct sbp2_login_response ) ,
2006-11-22 21:44:34 +01:00
& lu - > login_response_dma , GFP_KERNEL ) ;
2006-11-02 21:16:08 +01:00
if ( ! lu - > login_response )
2005-04-16 15:20:36 -07:00
goto alloc_fail ;
2006-12-29 23:47:04 +01:00
lu - > query_logins_orb = dma_alloc_coherent ( hi - > host - > device . parent ,
2005-11-07 06:31:39 -05:00
sizeof ( struct sbp2_query_logins_orb ) ,
2006-11-22 21:44:34 +01:00
& lu - > query_logins_orb_dma , GFP_KERNEL ) ;
2006-11-02 21:16:08 +01:00
if ( ! lu - > query_logins_orb )
2005-04-16 15:20:36 -07:00
goto alloc_fail ;
2006-12-29 23:47:04 +01:00
lu - > query_logins_response = dma_alloc_coherent ( hi - > host - > device . parent ,
2005-11-07 06:31:39 -05:00
sizeof ( struct sbp2_query_logins_response ) ,
2006-11-22 21:44:34 +01:00
& lu - > query_logins_response_dma , GFP_KERNEL ) ;
2006-11-02 21:16:08 +01:00
if ( ! lu - > query_logins_response )
2005-04-16 15:20:36 -07:00
goto alloc_fail ;
2006-12-29 23:47:04 +01:00
lu - > reconnect_orb = dma_alloc_coherent ( hi - > host - > device . parent ,
2005-11-07 06:31:39 -05:00
sizeof ( struct sbp2_reconnect_orb ) ,
2006-11-22 21:44:34 +01:00
& lu - > reconnect_orb_dma , GFP_KERNEL ) ;
2006-11-02 21:16:08 +01:00
if ( ! lu - > reconnect_orb )
2005-04-16 15:20:36 -07:00
goto alloc_fail ;
2006-12-29 23:47:04 +01:00
lu - > logout_orb = dma_alloc_coherent ( hi - > host - > device . parent ,
2005-11-07 06:31:39 -05:00
sizeof ( struct sbp2_logout_orb ) ,
2006-11-22 21:44:34 +01:00
& lu - > logout_orb_dma , GFP_KERNEL ) ;
2006-11-02 21:16:08 +01:00
if ( ! lu - > logout_orb )
2005-04-16 15:20:36 -07:00
goto alloc_fail ;
2006-12-29 23:47:04 +01:00
lu - > login_orb = dma_alloc_coherent ( hi - > host - > device . parent ,
2005-11-07 06:31:39 -05:00
sizeof ( struct sbp2_login_orb ) ,
2006-11-22 21:44:34 +01:00
& lu - > login_orb_dma , GFP_KERNEL ) ;
2006-11-02 21:16:08 +01:00
if ( ! lu - > login_orb )
2005-12-13 11:05:05 -05:00
goto alloc_fail ;
2005-04-16 15:20:36 -07:00
2007-02-04 20:57:38 +01:00
if ( sbp2util_create_command_orb_pool ( lu ) )
goto alloc_fail ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
/* Wait a second before trying to log in. Previously logged in
* initiators need a chance to reconnect . */
2006-08-14 18:56:00 +02:00
if ( msleep_interruptible ( 1000 ) ) {
2006-11-02 21:16:08 +01:00
sbp2_remove_device ( lu ) ;
2005-04-16 15:20:36 -07:00
return - EINTR ;
}
2005-11-07 06:31:39 -05:00
2006-11-02 21:16:08 +01:00
if ( sbp2_login_device ( lu ) ) {
sbp2_remove_device ( lu ) ;
2005-04-16 15:20:36 -07:00
return - EBUSY ;
}
2006-11-02 21:16:08 +01:00
sbp2_set_busy_timeout ( lu ) ;
sbp2_agent_reset ( lu , 1 ) ;
sbp2_max_speed_and_size ( lu ) ;
2005-04-16 15:20:36 -07:00
2008-02-03 23:07:44 +01:00
if ( lu - > workarounds & SBP2_WORKAROUND_DELAY_INQUIRY )
ssleep ( SBP2_INQUIRY_DELAY ) ;
2006-11-02 21:16:08 +01:00
error = scsi_add_device ( lu - > shost , 0 , lu - > ud - > id , 0 ) ;
2005-09-10 12:44:09 -05:00
if ( error ) {
2005-04-16 15:20:36 -07:00
SBP2_ERR ( " scsi_add_device failed " ) ;
2006-11-02 21:16:08 +01:00
sbp2_logout_device ( lu ) ;
sbp2_remove_device ( lu ) ;
2005-09-10 12:44:09 -05:00
return error ;
2005-04-16 15:20:36 -07:00
}
return 0 ;
2005-12-13 11:05:05 -05:00
alloc_fail :
2006-11-02 21:16:08 +01:00
SBP2_ERR ( " Could not allocate memory for lu " ) ;
sbp2_remove_device ( lu ) ;
2005-12-13 11:05:05 -05:00
return - ENOMEM ;
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
static void sbp2_remove_device ( struct sbp2_lu * lu )
2005-04-16 15:20:36 -07:00
{
2006-11-02 21:16:08 +01:00
struct sbp2_fwhost_info * hi ;
2007-08-11 11:52:08 +02:00
unsigned long flags ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
if ( ! lu )
2005-04-16 15:20:36 -07:00
return ;
2006-11-02 21:16:08 +01:00
hi = lu - > hi ;
2007-08-11 11:51:16 +02:00
if ( ! hi )
goto no_hi ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
if ( lu - > shost ) {
scsi_remove_host ( lu - > shost ) ;
scsi_host_put ( lu - > shost ) ;
2005-04-16 15:20:36 -07:00
}
2006-08-14 18:43:00 +02:00
flush_scheduled_work ( ) ;
2007-08-11 11:51:16 +02:00
sbp2util_remove_command_orb_pool ( lu , hi - > host ) ;
2005-04-16 15:20:36 -07:00
2007-08-11 11:52:08 +02:00
write_lock_irqsave ( & sbp2_hi_logical_units_lock , flags ) ;
2006-11-02 21:16:08 +01:00
list_del ( & lu - > lu_list ) ;
2007-08-11 11:52:08 +02:00
write_unlock_irqrestore ( & sbp2_hi_logical_units_lock , flags ) ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
if ( lu - > login_response )
2006-12-29 23:47:04 +01:00
dma_free_coherent ( hi - > host - > device . parent ,
2005-04-16 15:20:36 -07:00
sizeof ( struct sbp2_login_response ) ,
2006-11-02 21:16:08 +01:00
lu - > login_response ,
lu - > login_response_dma ) ;
if ( lu - > login_orb )
2006-12-29 23:47:04 +01:00
dma_free_coherent ( hi - > host - > device . parent ,
2005-04-16 15:20:36 -07:00
sizeof ( struct sbp2_login_orb ) ,
2006-11-02 21:16:08 +01:00
lu - > login_orb ,
lu - > login_orb_dma ) ;
if ( lu - > reconnect_orb )
2006-12-29 23:47:04 +01:00
dma_free_coherent ( hi - > host - > device . parent ,
2005-04-16 15:20:36 -07:00
sizeof ( struct sbp2_reconnect_orb ) ,
2006-11-02 21:16:08 +01:00
lu - > reconnect_orb ,
lu - > reconnect_orb_dma ) ;
if ( lu - > logout_orb )
2006-12-29 23:47:04 +01:00
dma_free_coherent ( hi - > host - > device . parent ,
2005-04-16 15:20:36 -07:00
sizeof ( struct sbp2_logout_orb ) ,
2006-11-02 21:16:08 +01:00
lu - > logout_orb ,
lu - > logout_orb_dma ) ;
if ( lu - > query_logins_orb )
2006-12-29 23:47:04 +01:00
dma_free_coherent ( hi - > host - > device . parent ,
2005-04-16 15:20:36 -07:00
sizeof ( struct sbp2_query_logins_orb ) ,
2006-11-02 21:16:08 +01:00
lu - > query_logins_orb ,
lu - > query_logins_orb_dma ) ;
if ( lu - > query_logins_response )
2006-12-29 23:47:04 +01:00
dma_free_coherent ( hi - > host - > device . parent ,
2005-04-16 15:20:36 -07:00
sizeof ( struct sbp2_query_logins_response ) ,
2006-11-02 21:16:08 +01:00
lu - > query_logins_response ,
lu - > query_logins_response_dma ) ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
if ( lu - > status_fifo_addr ! = CSR1212_INVALID_ADDR_SPACE )
2006-01-31 00:13:33 -05:00
hpsb_unregister_addrspace ( & sbp2_highlevel , hi - > host ,
2006-11-02 21:16:08 +01:00
lu - > status_fifo_addr ) ;
2006-01-31 00:13:33 -05:00
2006-11-02 21:16:08 +01:00
lu - > ud - > device . driver_data = NULL ;
2005-04-16 15:20:36 -07:00
2007-08-11 11:51:16 +02:00
module_put ( hi - > host - > driver - > owner ) ;
no_hi :
2006-11-02 21:16:08 +01:00
kfree ( lu ) ;
2005-04-16 15:20:36 -07:00
}
# ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
/*
2006-11-02 21:16:08 +01:00
* Deal with write requests on adapters which do not support physical DMA or
* have it switched off .
2005-04-16 15:20:36 -07:00
*/
2005-11-07 06:31:39 -05:00
static int sbp2_handle_physdma_write ( struct hpsb_host * host , int nodeid ,
int destid , quadlet_t * data , u64 addr ,
size_t length , u16 flags )
2005-04-16 15:20:36 -07:00
{
2005-11-07 06:31:39 -05:00
memcpy ( bus_to_virt ( ( u32 ) addr ) , data , length ) ;
return RCODE_COMPLETE ;
2005-04-16 15:20:36 -07:00
}
/*
2006-11-02 21:16:08 +01:00
* Deal with read requests on adapters which do not support physical DMA or
* have it switched off .
2005-04-16 15:20:36 -07:00
*/
2005-11-07 06:31:39 -05:00
static int sbp2_handle_physdma_read ( struct hpsb_host * host , int nodeid ,
quadlet_t * data , u64 addr , size_t length ,
u16 flags )
2005-04-16 15:20:36 -07:00
{
2005-11-07 06:31:39 -05:00
memcpy ( data , bus_to_virt ( ( u32 ) addr ) , length ) ;
return RCODE_COMPLETE ;
2005-04-16 15:20:36 -07:00
}
# endif
/**************************************
* SBP - 2 protocol related section
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-11-02 21:16:08 +01:00
static int sbp2_query_logins ( struct sbp2_lu * lu )
2005-04-16 15:20:36 -07:00
{
2006-11-02 21:16:08 +01:00
struct sbp2_fwhost_info * hi = lu - > hi ;
2005-04-16 15:20:36 -07:00
quadlet_t data [ 2 ] ;
int max_logins ;
int active_logins ;
2006-11-02 21:16:08 +01:00
lu - > query_logins_orb - > reserved1 = 0x0 ;
lu - > query_logins_orb - > reserved2 = 0x0 ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
lu - > query_logins_orb - > query_response_lo = lu - > query_logins_response_dma ;
lu - > query_logins_orb - > query_response_hi =
ORB_SET_NODE_ID ( hi - > host - > node_id ) ;
lu - > query_logins_orb - > lun_misc =
ORB_SET_FUNCTION ( SBP2_QUERY_LOGINS_REQUEST ) ;
lu - > query_logins_orb - > lun_misc | = ORB_SET_NOTIFY ( 1 ) ;
lu - > query_logins_orb - > lun_misc | = ORB_SET_LUN ( lu - > lun ) ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
lu - > query_logins_orb - > reserved_resp_length =
ORB_SET_QUERY_LOGINS_RESP_LENGTH (
sizeof ( struct sbp2_query_logins_response ) ) ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
lu - > query_logins_orb - > status_fifo_hi =
ORB_SET_STATUS_FIFO_HI ( lu - > status_fifo_addr , hi - > host - > node_id ) ;
lu - > query_logins_orb - > status_fifo_lo =
ORB_SET_STATUS_FIFO_LO ( lu - > status_fifo_addr ) ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
sbp2util_cpu_to_be32_buffer ( lu - > query_logins_orb ,
sizeof ( struct sbp2_query_logins_orb ) ) ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
memset ( lu - > query_logins_response , 0 ,
sizeof ( struct sbp2_query_logins_response ) ) ;
2005-04-16 15:20:36 -07:00
data [ 0 ] = ORB_SET_NODE_ID ( hi - > host - > node_id ) ;
2006-11-02 21:16:08 +01:00
data [ 1 ] = lu - > query_logins_orb_dma ;
2005-04-16 15:20:36 -07:00
sbp2util_cpu_to_be32_buffer ( data , 8 ) ;
2006-11-02 21:16:08 +01:00
hpsb_node_write ( lu - > ne , lu - > management_agent_addr , data , 8 ) ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
if ( sbp2util_access_timeout ( lu , 2 * HZ ) ) {
2005-04-16 15:20:36 -07:00
SBP2_INFO ( " Error querying logins to SBP-2 device - timed out " ) ;
2005-11-07 06:31:39 -05:00
return - EIO ;
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
if ( lu - > status_block . ORB_offset_lo ! = lu - > query_logins_orb_dma ) {
2005-04-16 15:20:36 -07:00
SBP2_INFO ( " Error querying logins to SBP-2 device - timed out " ) ;
2005-11-07 06:31:39 -05:00
return - EIO ;
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
if ( STATUS_TEST_RDS ( lu - > status_block . ORB_offset_hi_misc ) ) {
2006-07-23 22:18:00 +02:00
SBP2_INFO ( " Error querying logins to SBP-2 device - failed " ) ;
2005-11-07 06:31:39 -05:00
return - EIO ;
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
sbp2util_cpu_to_be32_buffer ( lu - > query_logins_response ,
sizeof ( struct sbp2_query_logins_response ) ) ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
max_logins = RESPONSE_GET_MAX_LOGINS (
lu - > query_logins_response - > length_max_logins ) ;
2006-06-12 18:13:11 -04:00
SBP2_INFO ( " Maximum concurrent logins supported: %d " , max_logins ) ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
active_logins = RESPONSE_GET_ACTIVE_LOGINS (
lu - > query_logins_response - > length_max_logins ) ;
2006-06-12 18:13:11 -04:00
SBP2_INFO ( " Number of active logins: %d " , active_logins ) ;
2005-04-16 15:20:36 -07:00
if ( active_logins > = max_logins ) {
2005-11-07 06:31:39 -05:00
return - EIO ;
2005-04-16 15:20:36 -07:00
}
return 0 ;
}
2006-11-02 21:16:08 +01:00
static int sbp2_login_device ( struct sbp2_lu * lu )
2005-04-16 15:20:36 -07:00
{
2006-11-02 21:16:08 +01:00
struct sbp2_fwhost_info * hi = lu - > hi ;
2005-04-16 15:20:36 -07:00
quadlet_t data [ 2 ] ;
2006-11-02 21:16:08 +01:00
if ( ! lu - > login_orb )
2005-11-07 06:31:39 -05:00
return - EIO ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
if ( ! sbp2_exclusive_login & & sbp2_query_logins ( lu ) ) {
2006-11-02 21:16:08 +01:00
SBP2_INFO ( " Device does not support any more concurrent logins " ) ;
return - EIO ;
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
/* assume no password */
2006-11-02 21:16:08 +01:00
lu - > login_orb - > password_hi = 0 ;
lu - > login_orb - > password_lo = 0 ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
lu - > login_orb - > login_response_lo = lu - > login_response_dma ;
lu - > login_orb - > login_response_hi = ORB_SET_NODE_ID ( hi - > host - > node_id ) ;
lu - > login_orb - > lun_misc = ORB_SET_FUNCTION ( SBP2_LOGIN_REQUEST ) ;
2006-11-02 21:16:08 +01:00
/* one second reconnect time */
2006-11-02 21:16:08 +01:00
lu - > login_orb - > lun_misc | = ORB_SET_RECONNECT ( 0 ) ;
lu - > login_orb - > lun_misc | = ORB_SET_EXCLUSIVE ( sbp2_exclusive_login ) ;
lu - > login_orb - > lun_misc | = ORB_SET_NOTIFY ( 1 ) ;
lu - > login_orb - > lun_misc | = ORB_SET_LUN ( lu - > lun ) ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
lu - > login_orb - > passwd_resp_lengths =
2005-04-16 15:20:36 -07:00
ORB_SET_LOGIN_RESP_LENGTH ( sizeof ( struct sbp2_login_response ) ) ;
2006-11-02 21:16:08 +01:00
lu - > login_orb - > status_fifo_hi =
ORB_SET_STATUS_FIFO_HI ( lu - > status_fifo_addr , hi - > host - > node_id ) ;
lu - > login_orb - > status_fifo_lo =
ORB_SET_STATUS_FIFO_LO ( lu - > status_fifo_addr ) ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
sbp2util_cpu_to_be32_buffer ( lu - > login_orb ,
sizeof ( struct sbp2_login_orb ) ) ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
memset ( lu - > login_response , 0 , sizeof ( struct sbp2_login_response ) ) ;
2005-04-16 15:20:36 -07:00
data [ 0 ] = ORB_SET_NODE_ID ( hi - > host - > node_id ) ;
2006-11-02 21:16:08 +01:00
data [ 1 ] = lu - > login_orb_dma ;
2005-04-16 15:20:36 -07:00
sbp2util_cpu_to_be32_buffer ( data , 8 ) ;
2006-11-02 21:16:08 +01:00
hpsb_node_write ( lu - > ne , lu - > management_agent_addr , data , 8 ) ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
/* wait up to 20 seconds for login status */
2006-11-02 21:16:08 +01:00
if ( sbp2util_access_timeout ( lu , 20 * HZ ) ) {
2006-07-23 22:19:00 +02:00
SBP2_ERR ( " Error logging into SBP-2 device - timed out " ) ;
2005-11-07 06:31:39 -05:00
return - EIO ;
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
/* make sure that the returned status matches the login ORB */
2006-11-02 21:16:08 +01:00
if ( lu - > status_block . ORB_offset_lo ! = lu - > login_orb_dma ) {
2006-07-23 22:18:00 +02:00
SBP2_ERR ( " Error logging into SBP-2 device - timed out " ) ;
2005-11-07 06:31:39 -05:00
return - EIO ;
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
if ( STATUS_TEST_RDS ( lu - > status_block . ORB_offset_hi_misc ) ) {
2006-07-23 22:18:00 +02:00
SBP2_ERR ( " Error logging into SBP-2 device - failed " ) ;
2005-11-07 06:31:39 -05:00
return - EIO ;
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
sbp2util_cpu_to_be32_buffer ( lu - > login_response ,
sizeof ( struct sbp2_login_response ) ) ;
lu - > command_block_agent_addr =
( ( u64 ) lu - > login_response - > command_block_agent_hi ) < < 32 ;
lu - > command_block_agent_addr | =
( ( u64 ) lu - > login_response - > command_block_agent_lo ) ;
lu - > command_block_agent_addr & = 0x0000ffffffffffffULL ;
2005-04-16 15:20:36 -07:00
SBP2_INFO ( " Logged into SBP-2 device " ) ;
2005-11-07 06:31:39 -05:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
static int sbp2_logout_device ( struct sbp2_lu * lu )
2005-04-16 15:20:36 -07:00
{
2006-11-02 21:16:08 +01:00
struct sbp2_fwhost_info * hi = lu - > hi ;
2005-04-16 15:20:36 -07:00
quadlet_t data [ 2 ] ;
int error ;
2006-11-02 21:16:08 +01:00
lu - > logout_orb - > reserved1 = 0x0 ;
lu - > logout_orb - > reserved2 = 0x0 ;
lu - > logout_orb - > reserved3 = 0x0 ;
lu - > logout_orb - > reserved4 = 0x0 ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
lu - > logout_orb - > login_ID_misc = ORB_SET_FUNCTION ( SBP2_LOGOUT_REQUEST ) ;
lu - > logout_orb - > login_ID_misc | =
ORB_SET_LOGIN_ID ( lu - > login_response - > length_login_ID ) ;
lu - > logout_orb - > login_ID_misc | = ORB_SET_NOTIFY ( 1 ) ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
lu - > logout_orb - > reserved5 = 0x0 ;
lu - > logout_orb - > status_fifo_hi =
ORB_SET_STATUS_FIFO_HI ( lu - > status_fifo_addr , hi - > host - > node_id ) ;
lu - > logout_orb - > status_fifo_lo =
ORB_SET_STATUS_FIFO_LO ( lu - > status_fifo_addr ) ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
sbp2util_cpu_to_be32_buffer ( lu - > logout_orb ,
sizeof ( struct sbp2_logout_orb ) ) ;
2005-04-16 15:20:36 -07:00
data [ 0 ] = ORB_SET_NODE_ID ( hi - > host - > node_id ) ;
2006-11-02 21:16:08 +01:00
data [ 1 ] = lu - > logout_orb_dma ;
2005-04-16 15:20:36 -07:00
sbp2util_cpu_to_be32_buffer ( data , 8 ) ;
2006-11-02 21:16:08 +01:00
error = hpsb_node_write ( lu - > ne , lu - > management_agent_addr , data , 8 ) ;
2005-04-16 15:20:36 -07:00
if ( error )
return error ;
2006-11-02 21:16:08 +01:00
/* wait up to 1 second for the device to complete logout */
2006-11-02 21:16:08 +01:00
if ( sbp2util_access_timeout ( lu , HZ ) )
2005-04-16 15:20:36 -07:00
return - EIO ;
SBP2_INFO ( " Logged out of SBP-2 device " ) ;
2005-11-07 06:31:39 -05:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
static int sbp2_reconnect_device ( struct sbp2_lu * lu )
2005-04-16 15:20:36 -07:00
{
2006-11-02 21:16:08 +01:00
struct sbp2_fwhost_info * hi = lu - > hi ;
2005-04-16 15:20:36 -07:00
quadlet_t data [ 2 ] ;
int error ;
2006-11-02 21:16:08 +01:00
lu - > reconnect_orb - > reserved1 = 0x0 ;
lu - > reconnect_orb - > reserved2 = 0x0 ;
lu - > reconnect_orb - > reserved3 = 0x0 ;
lu - > reconnect_orb - > reserved4 = 0x0 ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
lu - > reconnect_orb - > login_ID_misc =
ORB_SET_FUNCTION ( SBP2_RECONNECT_REQUEST ) ;
lu - > reconnect_orb - > login_ID_misc | =
ORB_SET_LOGIN_ID ( lu - > login_response - > length_login_ID ) ;
lu - > reconnect_orb - > login_ID_misc | = ORB_SET_NOTIFY ( 1 ) ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
lu - > reconnect_orb - > reserved5 = 0x0 ;
lu - > reconnect_orb - > status_fifo_hi =
ORB_SET_STATUS_FIFO_HI ( lu - > status_fifo_addr , hi - > host - > node_id ) ;
lu - > reconnect_orb - > status_fifo_lo =
ORB_SET_STATUS_FIFO_LO ( lu - > status_fifo_addr ) ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
sbp2util_cpu_to_be32_buffer ( lu - > reconnect_orb ,
sizeof ( struct sbp2_reconnect_orb ) ) ;
2005-04-16 15:20:36 -07:00
data [ 0 ] = ORB_SET_NODE_ID ( hi - > host - > node_id ) ;
2006-11-02 21:16:08 +01:00
data [ 1 ] = lu - > reconnect_orb_dma ;
2005-04-16 15:20:36 -07:00
sbp2util_cpu_to_be32_buffer ( data , 8 ) ;
2006-11-02 21:16:08 +01:00
error = hpsb_node_write ( lu - > ne , lu - > management_agent_addr , data , 8 ) ;
2005-04-16 15:20:36 -07:00
if ( error )
return error ;
2006-11-02 21:16:08 +01:00
/* wait up to 1 second for reconnect status */
2006-11-02 21:16:08 +01:00
if ( sbp2util_access_timeout ( lu , HZ ) ) {
2006-07-23 22:19:00 +02:00
SBP2_ERR ( " Error reconnecting to SBP-2 device - timed out " ) ;
2005-11-07 06:31:39 -05:00
return - EIO ;
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
/* make sure that the returned status matches the reconnect ORB */
2006-11-02 21:16:08 +01:00
if ( lu - > status_block . ORB_offset_lo ! = lu - > reconnect_orb_dma ) {
2006-07-23 22:18:00 +02:00
SBP2_ERR ( " Error reconnecting to SBP-2 device - timed out " ) ;
2005-11-07 06:31:39 -05:00
return - EIO ;
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
if ( STATUS_TEST_RDS ( lu - > status_block . ORB_offset_hi_misc ) ) {
2006-07-23 22:18:00 +02:00
SBP2_ERR ( " Error reconnecting to SBP-2 device - failed " ) ;
2005-11-07 06:31:39 -05:00
return - EIO ;
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
SBP2_INFO ( " Reconnected to SBP-2 device " ) ;
2005-11-07 06:31:39 -05:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
/*
2006-11-02 21:16:08 +01:00
* Set the target node ' s Single Phase Retry limit . Affects the target ' s retry
* behaviour if our node is too busy to accept requests .
2005-04-16 15:20:36 -07:00
*/
2006-11-02 21:16:08 +01:00
static int sbp2_set_busy_timeout ( struct sbp2_lu * lu )
2005-04-16 15:20:36 -07:00
{
quadlet_t data ;
data = cpu_to_be32 ( SBP2_BUSY_TIMEOUT_VALUE ) ;
2006-11-02 21:16:08 +01:00
if ( hpsb_node_write ( lu - > ne , SBP2_BUSY_TIMEOUT_ADDRESS , & data , 4 ) )
2008-03-05 18:24:54 -08:00
SBP2_ERR ( " %s error " , __func__ ) ;
2005-11-07 06:31:39 -05:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
static void sbp2_parse_unit_directory ( struct sbp2_lu * lu ,
2005-04-16 15:20:36 -07:00
struct unit_directory * ud )
{
struct csr1212_keyval * kv ;
struct csr1212_dentry * dentry ;
u64 management_agent_addr ;
2006-11-02 21:16:08 +01:00
u32 unit_characteristics , firmware_revision ;
2006-05-15 22:04:59 +02:00
unsigned workarounds ;
2005-04-16 15:20:36 -07:00
int i ;
2006-11-02 21:16:08 +01:00
management_agent_addr = 0 ;
unit_characteristics = 0 ;
firmware_revision = 0 ;
2005-04-16 15:20:36 -07:00
csr1212_for_each_dir_entry ( ud - > ne - > csr , kv , ud - > ud_kv , dentry ) {
switch ( kv - > key . id ) {
case CSR1212_KV_ID_DEPENDENT_INFO :
2006-11-02 21:16:08 +01:00
if ( kv - > key . type = = CSR1212_KV_TYPE_CSR_OFFSET )
2005-04-16 15:20:36 -07:00
management_agent_addr =
2005-11-07 06:31:39 -05:00
CSR1212_REGISTER_SPACE_BASE +
( kv - > value . csr_offset < < 2 ) ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
else if ( kv - > key . type = = CSR1212_KV_TYPE_IMMEDIATE )
2006-11-02 21:16:08 +01:00
lu - > lun = ORB_SET_LUN ( kv - > value . immediate ) ;
2005-04-16 15:20:36 -07:00
break ;
case SBP2_UNIT_CHARACTERISTICS_KEY :
2006-11-02 21:16:08 +01:00
/* FIXME: This is ignored so far.
* See SBP - 2 clause 7.4 .8 . */
2005-04-16 15:20:36 -07:00
unit_characteristics = kv - > value . immediate ;
break ;
case SBP2_FIRMWARE_REVISION_KEY :
firmware_revision = kv - > value . immediate ;
break ;
default :
2006-11-02 21:16:08 +01:00
/* FIXME: Check for SBP2_DEVICE_TYPE_AND_LUN_KEY.
* Its " ordered " bit has consequences for command ORB
* list handling . See SBP - 2 clauses 4.6 , 7.4 .11 , 10.2 */
2005-04-16 15:20:36 -07:00
break ;
}
}
2006-05-15 22:04:59 +02:00
workarounds = sbp2_default_workarounds ;
2005-04-16 15:20:36 -07:00
2006-05-15 22:08:09 +02:00
if ( ! ( workarounds & SBP2_WORKAROUND_OVERRIDE ) )
for ( i = 0 ; i < ARRAY_SIZE ( sbp2_workarounds_table ) ; i + + ) {
2006-12-30 15:37:09 +01:00
if ( sbp2_workarounds_table [ i ] . firmware_revision ! =
SBP2_ROM_VALUE_WILDCARD & &
2006-05-15 22:08:09 +02:00
sbp2_workarounds_table [ i ] . firmware_revision ! =
( firmware_revision & 0xffff00 ) )
continue ;
2006-12-30 15:37:09 +01:00
if ( sbp2_workarounds_table [ i ] . model_id ! =
SBP2_ROM_VALUE_WILDCARD & &
2006-05-15 22:08:09 +02:00
sbp2_workarounds_table [ i ] . model_id ! = ud - > model_id )
continue ;
workarounds | = sbp2_workarounds_table [ i ] . workarounds ;
break ;
}
2005-04-16 15:20:36 -07:00
2006-05-15 22:04:59 +02:00
if ( workarounds )
2006-05-15 22:06:37 +02:00
SBP2_INFO ( " Workarounds for node " NODE_BUS_FMT " : 0x%x "
" (firmware_revision 0x%06x, vendor_id 0x%06x, "
" model_id 0x%06x) " ,
2006-05-15 22:04:59 +02:00
NODE_BUS_ARGS ( ud - > ne - > host , ud - > ne - > nodeid ) ,
2006-05-15 22:06:37 +02:00
workarounds , firmware_revision ,
ud - > vendor_id ? ud - > vendor_id : ud - > ne - > vendor_id ,
ud - > model_id ) ;
2006-05-15 22:04:59 +02:00
/* We would need one SCSI host template for each target to adjust
* max_sectors on the fly , therefore warn only . */
if ( workarounds & SBP2_WORKAROUND_128K_MAX_TRANS & &
2006-11-02 21:16:08 +01:00
( sbp2_max_sectors * 512 ) > ( 128 * 1024 ) )
2006-11-02 21:16:08 +01:00
SBP2_INFO ( " Node " NODE_BUS_FMT " : Bridge only supports 128KB "
2006-05-15 22:04:59 +02:00
" max transfer size. WARNING: Current max_sectors "
" setting is larger than 128KB (%d sectors) " ,
NODE_BUS_ARGS ( ud - > ne - > host , ud - > ne - > nodeid ) ,
2006-11-02 21:16:08 +01:00
sbp2_max_sectors ) ;
2006-05-15 22:04:59 +02:00
2005-04-16 15:20:36 -07:00
/* If this is a logical unit directory entry, process the parent
* to get the values . */
if ( ud - > flags & UNIT_DIRECTORY_LUN_DIRECTORY ) {
2006-11-02 21:16:08 +01:00
struct unit_directory * parent_ud = container_of (
ud - > device . parent , struct unit_directory , device ) ;
sbp2_parse_unit_directory ( lu , parent_ud ) ;
2005-04-16 15:20:36 -07:00
} else {
2006-11-02 21:16:08 +01:00
lu - > management_agent_addr = management_agent_addr ;
lu - > workarounds = workarounds ;
2005-04-16 15:20:36 -07:00
if ( ud - > flags & UNIT_DIRECTORY_HAS_LUN )
2006-11-02 21:16:08 +01:00
lu - > lun = ORB_SET_LUN ( ud - > lun ) ;
2005-04-16 15:20:36 -07:00
}
}
2006-06-12 18:14:14 -04:00
# define SBP2_PAYLOAD_TO_BYTES(p) (1 << ((p) + 2))
2005-04-16 15:20:36 -07:00
/*
* This function is called in order to determine the max speed and packet
* size we can use in our ORBs . Note , that we ( the driver and host ) only
* initiate the transaction . The SBP - 2 device actually transfers the data
* ( by reading from the DMA area we tell it ) . This means that the SBP - 2
* device decides the actual maximum data it can transfer . We just tell it
* the speed that it needs to use , and the max_rec the host supports , and
* it takes care of the rest .
*/
2006-11-02 21:16:08 +01:00
static int sbp2_max_speed_and_size ( struct sbp2_lu * lu )
2005-04-16 15:20:36 -07:00
{
2006-11-02 21:16:08 +01:00
struct sbp2_fwhost_info * hi = lu - > hi ;
2006-06-12 18:14:14 -04:00
u8 payload ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
lu - > speed_code = hi - > host - > speed [ NODEID_TO_NODE ( lu - > ne - > nodeid ) ] ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
if ( lu - > speed_code > sbp2_max_speed ) {
lu - > speed_code = sbp2_max_speed ;
2006-11-02 21:16:08 +01:00
SBP2_INFO ( " Reducing speed to %s " ,
hpsb_speedto_str [ sbp2_max_speed ] ) ;
2005-04-16 15:20:36 -07:00
}
/* Payload size is the lesser of what our speed supports and what
* our host supports . */
2006-11-02 21:16:08 +01:00
payload = min ( sbp2_speedto_max_payload [ lu - > speed_code ] ,
2006-06-12 18:14:14 -04:00
( u8 ) ( hi - > host - > csr . max_rec - 1 ) ) ;
/* If physical DMA is off, work around limitation in ohci1394:
* packet size must not exceed PAGE_SIZE */
2006-11-02 21:16:08 +01:00
if ( lu - > ne - > host - > low_addr_space < ( 1ULL < < 32 ) )
2006-06-12 18:14:14 -04:00
while ( SBP2_PAYLOAD_TO_BYTES ( payload ) + 24 > PAGE_SIZE & &
payload )
payload - - ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
SBP2_INFO ( " Node " NODE_BUS_FMT " : Max speed [%s] - Max payload [%u] " ,
2006-11-02 21:16:08 +01:00
NODE_BUS_ARGS ( hi - > host , lu - > ne - > nodeid ) ,
hpsb_speedto_str [ lu - > speed_code ] ,
2006-11-02 21:16:08 +01:00
SBP2_PAYLOAD_TO_BYTES ( payload ) ) ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
lu - > max_payload_size = payload ;
2005-11-07 06:31:39 -05:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
static int sbp2_agent_reset ( struct sbp2_lu * lu , int wait )
2005-04-16 15:20:36 -07:00
{
quadlet_t data ;
u64 addr ;
int retval ;
2006-07-23 22:12:00 +02:00
unsigned long flags ;
2005-04-16 15:20:36 -07:00
2006-12-07 23:23:25 +01:00
/* flush lu->protocol_work */
2006-08-14 18:43:00 +02:00
if ( wait )
flush_scheduled_work ( ) ;
2005-04-16 15:20:36 -07:00
data = ntohl ( SBP2_AGENT_RESET_DATA ) ;
2006-11-02 21:16:08 +01:00
addr = lu - > command_block_agent_addr + SBP2_AGENT_RESET_OFFSET ;
2005-04-16 15:20:36 -07:00
if ( wait )
2006-11-02 21:16:08 +01:00
retval = hpsb_node_write ( lu - > ne , addr , & data , 4 ) ;
2005-04-16 15:20:36 -07:00
else
2006-11-02 21:16:08 +01:00
retval = sbp2util_node_write_no_wait ( lu - > ne , addr , & data , 4 ) ;
2005-04-16 15:20:36 -07:00
if ( retval < 0 ) {
SBP2_ERR ( " hpsb_node_write failed. \n " ) ;
return - EIO ;
}
2006-11-02 21:16:08 +01:00
/* make sure that the ORB_POINTER is written on next command */
2006-11-02 21:16:08 +01:00
spin_lock_irqsave ( & lu - > cmd_orb_lock , flags ) ;
lu - > last_orb = NULL ;
spin_unlock_irqrestore ( & lu - > cmd_orb_lock , flags ) ;
2005-04-16 15:20:36 -07:00
2005-11-07 06:31:39 -05:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
2005-12-13 11:05:03 -05:00
static void sbp2_prep_command_orb_sg ( struct sbp2_command_orb * orb ,
2006-11-02 21:16:08 +01:00
struct sbp2_fwhost_info * hi ,
2006-11-02 21:16:08 +01:00
struct sbp2_command_info * cmd ,
2005-12-13 11:05:03 -05:00
unsigned int scsi_use_sg ,
2007-11-04 14:59:24 +01:00
struct scatterlist * sg ,
2005-12-13 11:05:03 -05:00
u32 orb_direction ,
enum dma_data_direction dma_dir )
{
2006-11-02 21:16:08 +01:00
cmd - > dma_dir = dma_dir ;
2005-12-13 11:05:03 -05:00
orb - > data_descriptor_hi = ORB_SET_NODE_ID ( hi - > host - > node_id ) ;
orb - > misc | = ORB_SET_DIRECTION ( orb_direction ) ;
2006-11-02 21:16:08 +01:00
/* special case if only one element (and less than 64KB in size) */
2008-02-01 22:31:10 +01:00
if ( scsi_use_sg = = 1 & & sg - > length < = SBP2_MAX_SG_ELEMENT_LENGTH ) {
2005-12-13 11:05:03 -05:00
2008-02-01 22:31:10 +01:00
cmd - > dma_size = sg - > length ;
2006-11-02 21:16:08 +01:00
cmd - > dma_type = CMD_DMA_PAGE ;
2006-12-29 23:47:04 +01:00
cmd - > cmd_dma = dma_map_page ( hi - > host - > device . parent ,
2007-11-04 14:59:24 +01:00
sg_page ( sg ) , sg - > offset ,
2006-11-02 21:16:08 +01:00
cmd - > dma_size , cmd - > dma_dir ) ;
2005-12-13 11:05:03 -05:00
2006-11-02 21:16:08 +01:00
orb - > data_descriptor_lo = cmd - > cmd_dma ;
orb - > misc | = ORB_SET_DATA_SIZE ( cmd - > dma_size ) ;
2005-12-13 11:05:03 -05:00
} else {
struct sbp2_unrestricted_page_table * sg_element =
2006-11-02 21:16:08 +01:00
& cmd - > scatter_gather_element [ 0 ] ;
2005-12-13 11:05:03 -05:00
u32 sg_count , sg_len ;
dma_addr_t sg_addr ;
2007-11-04 14:59:24 +01:00
int i , count = dma_map_sg ( hi - > host - > device . parent , sg ,
2006-12-29 23:47:04 +01:00
scsi_use_sg , dma_dir ) ;
2005-12-13 11:05:03 -05:00
2006-11-02 21:16:08 +01:00
cmd - > dma_size = scsi_use_sg ;
2007-11-04 14:59:24 +01:00
cmd - > sge_buffer = sg ;
2005-12-13 11:05:03 -05:00
/* use page tables (s/g) */
orb - > misc | = ORB_SET_PAGE_TABLE_PRESENT ( 0x1 ) ;
2006-11-02 21:16:08 +01:00
orb - > data_descriptor_lo = cmd - > sge_dma ;
2005-12-13 11:05:03 -05:00
2006-11-02 21:16:08 +01:00
/* loop through and fill out our SBP-2 page tables
* ( and split up anything too large ) */
2007-11-04 14:59:24 +01:00
for ( i = 0 , sg_count = 0 ; i < count ; i + + , sg = sg_next ( sg ) ) {
sg_len = sg_dma_len ( sg ) ;
sg_addr = sg_dma_address ( sg ) ;
2005-12-13 11:05:03 -05:00
while ( sg_len ) {
sg_element [ sg_count ] . segment_base_lo = sg_addr ;
if ( sg_len > SBP2_MAX_SG_ELEMENT_LENGTH ) {
sg_element [ sg_count ] . length_segment_base_hi =
PAGE_TABLE_SET_SEGMENT_LENGTH ( SBP2_MAX_SG_ELEMENT_LENGTH ) ;
sg_addr + = SBP2_MAX_SG_ELEMENT_LENGTH ;
sg_len - = SBP2_MAX_SG_ELEMENT_LENGTH ;
} else {
sg_element [ sg_count ] . length_segment_base_hi =
PAGE_TABLE_SET_SEGMENT_LENGTH ( sg_len ) ;
sg_len = 0 ;
}
sg_count + + ;
}
}
orb - > misc | = ORB_SET_DATA_SIZE ( sg_count ) ;
sbp2util_cpu_to_be32_buffer ( sg_element ,
2006-11-02 21:16:08 +01:00
( sizeof ( struct sbp2_unrestricted_page_table ) ) *
sg_count ) ;
2005-12-13 11:05:03 -05:00
}
}
2006-11-02 21:16:08 +01:00
static void sbp2_create_command_orb ( struct sbp2_lu * lu ,
struct sbp2_command_info * cmd ,
2005-12-13 11:05:03 -05:00
unchar * scsi_cmd ,
unsigned int scsi_use_sg ,
unsigned int scsi_request_bufflen ,
2007-11-04 14:59:24 +01:00
struct scatterlist * sg ,
2005-12-13 11:05:03 -05:00
enum dma_data_direction dma_dir )
2005-04-16 15:20:36 -07:00
{
2006-11-02 21:16:08 +01:00
struct sbp2_fwhost_info * hi = lu - > hi ;
struct sbp2_command_orb * orb = & cmd - > command_orb ;
2005-12-13 11:05:03 -05:00
u32 orb_direction ;
2005-04-16 15:20:36 -07:00
/*
2006-11-02 21:16:08 +01:00
* Set - up our command ORB .
2005-04-16 15:20:36 -07:00
*
* NOTE : We ' re doing unrestricted page tables ( s / g ) , as this is
* best performance ( at least with the devices I have ) . This means
* that data_size becomes the number of s / g elements , and
* page_size should be zero ( for unrestricted ) .
*/
2006-11-02 21:16:08 +01:00
orb - > next_ORB_hi = ORB_SET_NULL_PTR ( 1 ) ;
orb - > next_ORB_lo = 0x0 ;
orb - > misc = ORB_SET_MAX_PAYLOAD ( lu - > max_payload_size ) ;
orb - > misc | = ORB_SET_SPEED ( lu - > speed_code ) ;
orb - > misc | = ORB_SET_NOTIFY ( 1 ) ;
2005-04-16 15:20:36 -07:00
2005-12-12 23:03:24 -05:00
if ( dma_dir = = DMA_NONE )
2005-11-07 06:31:39 -05:00
orb_direction = ORB_DIRECTION_NO_DATA_TRANSFER ;
2005-12-12 23:03:24 -05:00
else if ( dma_dir = = DMA_TO_DEVICE & & scsi_request_bufflen )
2005-11-07 06:31:39 -05:00
orb_direction = ORB_DIRECTION_WRITE_TO_MEDIA ;
2005-12-12 23:03:24 -05:00
else if ( dma_dir = = DMA_FROM_DEVICE & & scsi_request_bufflen )
2005-11-07 06:31:39 -05:00
orb_direction = ORB_DIRECTION_READ_FROM_MEDIA ;
2005-12-12 23:03:24 -05:00
else {
2006-11-02 21:16:08 +01:00
SBP2_INFO ( " Falling back to DMA_NONE " ) ;
2005-12-12 23:03:24 -05:00
orb_direction = ORB_DIRECTION_NO_DATA_TRANSFER ;
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
/* set up our page table stuff */
2005-04-16 15:20:36 -07:00
if ( orb_direction = = ORB_DIRECTION_NO_DATA_TRANSFER ) {
2006-11-02 21:16:08 +01:00
orb - > data_descriptor_hi = 0x0 ;
orb - > data_descriptor_lo = 0x0 ;
orb - > misc | = ORB_SET_DIRECTION ( 1 ) ;
2007-05-14 20:00:04 +09:00
} else
2007-11-04 14:59:24 +01:00
sbp2_prep_command_orb_sg ( orb , hi , cmd , scsi_use_sg , sg ,
2006-11-02 21:16:08 +01:00
orb_direction , dma_dir ) ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
sbp2util_cpu_to_be32_buffer ( orb , sizeof ( * orb ) ) ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
memset ( orb - > cdb , 0 , 12 ) ;
memcpy ( orb - > cdb , scsi_cmd , COMMAND_SIZE ( * scsi_cmd ) ) ;
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
static void sbp2_link_orb_command ( struct sbp2_lu * lu ,
struct sbp2_command_info * cmd )
2005-04-16 15:20:36 -07:00
{
2006-11-02 21:16:08 +01:00
struct sbp2_fwhost_info * hi = lu - > hi ;
2006-07-23 22:12:00 +02:00
struct sbp2_command_orb * last_orb ;
dma_addr_t last_orb_dma ;
2006-11-02 21:16:08 +01:00
u64 addr = lu - > command_block_agent_addr ;
2006-07-23 22:12:00 +02:00
quadlet_t data [ 2 ] ;
size_t length ;
unsigned long flags ;
2005-04-16 15:20:36 -07:00
2006-12-29 23:47:04 +01:00
dma_sync_single_for_device ( hi - > host - > device . parent ,
cmd - > command_orb_dma ,
2006-11-22 21:44:34 +01:00
sizeof ( struct sbp2_command_orb ) ,
DMA_TO_DEVICE ) ;
2006-12-29 23:47:04 +01:00
dma_sync_single_for_device ( hi - > host - > device . parent , cmd - > sge_dma ,
2006-11-22 21:44:34 +01:00
sizeof ( cmd - > scatter_gather_element ) ,
2007-02-04 20:54:57 +01:00
DMA_TO_DEVICE ) ;
2006-11-02 21:16:08 +01:00
/* check to see if there are any previous orbs to use */
2006-11-02 21:16:08 +01:00
spin_lock_irqsave ( & lu - > cmd_orb_lock , flags ) ;
last_orb = lu - > last_orb ;
last_orb_dma = lu - > last_orb_dma ;
2006-07-23 22:12:00 +02:00
if ( ! last_orb ) {
2005-04-16 15:20:36 -07:00
/*
2006-07-23 22:12:00 +02:00
* last_orb = = NULL means : We know that the target ' s fetch agent
* is not active right now .
2005-04-16 15:20:36 -07:00
*/
2006-07-23 22:12:00 +02:00
addr + = SBP2_ORB_POINTER_OFFSET ;
2005-04-16 15:20:36 -07:00
data [ 0 ] = ORB_SET_NODE_ID ( hi - > host - > node_id ) ;
2006-11-02 21:16:08 +01:00
data [ 1 ] = cmd - > command_orb_dma ;
2005-04-16 15:20:36 -07:00
sbp2util_cpu_to_be32_buffer ( data , 8 ) ;
2006-07-23 22:12:00 +02:00
length = 8 ;
2005-04-16 15:20:36 -07:00
} else {
/*
2006-07-23 22:12:00 +02:00
* last_orb ! = NULL means : We know that the target ' s fetch agent
* is ( very probably ) not dead or in reset state right now .
* We have an ORB already sent that we can append a new one to .
* The target ' s fetch agent may or may not have read this
* previous ORB yet .
2005-04-16 15:20:36 -07:00
*/
2006-12-29 23:47:04 +01:00
dma_sync_single_for_cpu ( hi - > host - > device . parent , last_orb_dma ,
2006-11-22 21:44:34 +01:00
sizeof ( struct sbp2_command_orb ) ,
DMA_TO_DEVICE ) ;
2006-11-02 21:16:08 +01:00
last_orb - > next_ORB_lo = cpu_to_be32 ( cmd - > command_orb_dma ) ;
2006-07-23 22:12:00 +02:00
wmb ( ) ;
2005-04-16 15:20:36 -07:00
/* Tells hardware that this pointer is valid */
2006-07-23 22:12:00 +02:00
last_orb - > next_ORB_hi = 0 ;
2006-12-29 23:47:04 +01:00
dma_sync_single_for_device ( hi - > host - > device . parent ,
last_orb_dma ,
2006-11-22 21:44:34 +01:00
sizeof ( struct sbp2_command_orb ) ,
DMA_TO_DEVICE ) ;
2006-07-23 22:12:00 +02:00
addr + = SBP2_DOORBELL_OFFSET ;
data [ 0 ] = 0 ;
length = 4 ;
}
2006-11-02 21:16:08 +01:00
lu - > last_orb = & cmd - > command_orb ;
lu - > last_orb_dma = cmd - > command_orb_dma ;
spin_unlock_irqrestore ( & lu - > cmd_orb_lock , flags ) ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
if ( sbp2util_node_write_no_wait ( lu - > ne , addr , data , length ) ) {
2006-08-14 18:43:00 +02:00
/*
* sbp2util_node_write_no_wait failed . We certainly ran out
* of transaction labels , perhaps just because there were no
* context switches which gave khpsbpkt a chance to collect
* free tlabels . Try again in non - atomic context . If necessary ,
* the workqueue job will sleep to guaranteedly get a tlabel .
* We do not accept new commands until the job is over .
*/
2006-11-02 21:16:08 +01:00
scsi_block_requests ( lu - > shost ) ;
PREPARE_WORK ( & lu - > protocol_work ,
2006-08-14 18:43:00 +02:00
last_orb ? sbp2util_write_doorbell :
2006-12-07 23:23:25 +01:00
sbp2util_write_orb_pointer ) ;
2006-11-02 21:16:08 +01:00
schedule_work ( & lu - > protocol_work ) ;
2006-08-14 18:43:00 +02:00
}
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
static int sbp2_send_command ( struct sbp2_lu * lu , struct scsi_cmnd * SCpnt ,
2005-04-16 15:20:36 -07:00
void ( * done ) ( struct scsi_cmnd * ) )
{
2006-11-02 21:16:08 +01:00
unchar * scsi_cmd = ( unchar * ) SCpnt - > cmnd ;
struct sbp2_command_info * cmd ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
cmd = sbp2util_allocate_command_orb ( lu , SCpnt , done ) ;
if ( ! cmd )
2005-11-07 06:31:39 -05:00
return - EIO ;
2005-04-16 15:20:36 -07:00
2007-05-14 20:00:04 +09:00
sbp2_create_command_orb ( lu , cmd , scsi_cmd , scsi_sg_count ( SCpnt ) ,
2007-11-04 14:59:24 +01:00
scsi_bufflen ( SCpnt ) , scsi_sglist ( SCpnt ) ,
2005-04-16 15:20:36 -07:00
SCpnt - > sc_data_direction ) ;
2006-11-02 21:16:08 +01:00
sbp2_link_orb_command ( lu , cmd ) ;
2005-04-16 15:20:36 -07:00
2005-11-07 06:31:39 -05:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
/*
* Translates SBP - 2 status into SCSI sense data for check conditions
*/
2006-11-02 21:16:08 +01:00
static unsigned int sbp2_status_to_sense_data ( unchar * sbp2_status ,
unchar * sense_data )
2005-04-16 15:20:36 -07:00
{
2006-11-02 21:16:08 +01:00
/* OK, it's pretty ugly... ;-) */
2005-04-16 15:20:36 -07:00
sense_data [ 0 ] = 0x70 ;
sense_data [ 1 ] = 0x0 ;
sense_data [ 2 ] = sbp2_status [ 9 ] ;
sense_data [ 3 ] = sbp2_status [ 12 ] ;
sense_data [ 4 ] = sbp2_status [ 13 ] ;
sense_data [ 5 ] = sbp2_status [ 14 ] ;
sense_data [ 6 ] = sbp2_status [ 15 ] ;
sense_data [ 7 ] = 10 ;
sense_data [ 8 ] = sbp2_status [ 16 ] ;
sense_data [ 9 ] = sbp2_status [ 17 ] ;
sense_data [ 10 ] = sbp2_status [ 18 ] ;
sense_data [ 11 ] = sbp2_status [ 19 ] ;
sense_data [ 12 ] = sbp2_status [ 10 ] ;
sense_data [ 13 ] = sbp2_status [ 11 ] ;
sense_data [ 14 ] = sbp2_status [ 20 ] ;
sense_data [ 15 ] = sbp2_status [ 21 ] ;
2006-11-02 21:16:08 +01:00
return sbp2_status [ 8 ] & 0x3f ;
2005-04-16 15:20:36 -07:00
}
2006-07-23 22:16:00 +02:00
static int sbp2_handle_status_write ( struct hpsb_host * host , int nodeid ,
int destid , quadlet_t * data , u64 addr ,
size_t length , u16 fl )
2005-04-16 15:20:36 -07:00
{
2006-11-02 21:16:08 +01:00
struct sbp2_fwhost_info * hi ;
2006-11-02 21:16:08 +01:00
struct sbp2_lu * lu = NULL , * lu_tmp ;
2005-04-16 15:20:36 -07:00
struct scsi_cmnd * SCpnt = NULL ;
2006-07-23 22:16:00 +02:00
struct sbp2_status_block * sb ;
2005-04-16 15:20:36 -07:00
u32 scsi_status = SBP2_SCSI_STATUS_GOOD ;
2006-11-02 21:16:08 +01:00
struct sbp2_command_info * cmd ;
2005-11-07 06:29:39 -05:00
unsigned long flags ;
2005-04-16 15:20:36 -07:00
2006-07-23 22:18:00 +02:00
if ( unlikely ( length < 8 | | length > sizeof ( struct sbp2_status_block ) ) ) {
SBP2_ERR ( " Wrong size of status block " ) ;
return RCODE_ADDRESS_ERROR ;
}
if ( unlikely ( ! host ) ) {
2005-04-16 15:20:36 -07:00
SBP2_ERR ( " host is NULL - this is bad! " ) ;
2005-11-07 06:31:39 -05:00
return RCODE_ADDRESS_ERROR ;
2005-04-16 15:20:36 -07:00
}
hi = hpsb_get_hostinfo ( & sbp2_highlevel , host ) ;
2006-07-23 22:18:00 +02:00
if ( unlikely ( ! hi ) ) {
2005-04-16 15:20:36 -07:00
SBP2_ERR ( " host info is NULL - this is bad! " ) ;
2005-11-07 06:31:39 -05:00
return RCODE_ADDRESS_ERROR ;
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
/* Find the unit which wrote the status. */
2007-08-11 11:52:08 +02:00
read_lock_irqsave ( & sbp2_hi_logical_units_lock , flags ) ;
2006-11-02 21:16:08 +01:00
list_for_each_entry ( lu_tmp , & hi - > logical_units , lu_list ) {
if ( lu_tmp - > ne - > nodeid = = nodeid & &
lu_tmp - > status_fifo_addr = = addr ) {
lu = lu_tmp ;
2005-04-16 15:20:36 -07:00
break ;
}
}
2007-08-11 11:52:08 +02:00
read_unlock_irqrestore ( & sbp2_hi_logical_units_lock , flags ) ;
2006-11-02 21:16:08 +01:00
if ( unlikely ( ! lu ) ) {
SBP2_ERR ( " lu is NULL - device is gone? " ) ;
2005-11-07 06:31:39 -05:00
return RCODE_ADDRESS_ERROR ;
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
/* Put response into lu status fifo buffer. The first two bytes
2006-07-23 22:16:00 +02:00
* come in big endian bit order . Often the target writes only a
* truncated status block , minimally the first two quadlets . The rest
2006-11-02 21:16:08 +01:00
* is implied to be zeros . */
2006-11-02 21:16:08 +01:00
sb = & lu - > status_block ;
2006-07-23 22:16:00 +02:00
memset ( sb - > command_set_dependent , 0 , sizeof ( sb - > command_set_dependent ) ) ;
memcpy ( sb , data , length ) ;
sbp2util_be32_to_cpu_buffer ( sb , 8 ) ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
/* Ignore unsolicited status. Handle command ORB status. */
2006-07-23 22:18:00 +02:00
if ( unlikely ( STATUS_GET_SRC ( sb - > ORB_offset_hi_misc ) = = 2 ) )
2006-11-02 21:16:08 +01:00
cmd = NULL ;
2006-07-23 22:18:00 +02:00
else
2006-11-02 21:16:08 +01:00
cmd = sbp2util_find_command_for_orb ( lu , sb - > ORB_offset_lo ) ;
if ( cmd ) {
2006-12-29 23:47:04 +01:00
dma_sync_single_for_cpu ( hi - > host - > device . parent ,
cmd - > command_orb_dma ,
2006-11-22 21:44:34 +01:00
sizeof ( struct sbp2_command_orb ) ,
DMA_TO_DEVICE ) ;
2006-12-29 23:47:04 +01:00
dma_sync_single_for_cpu ( hi - > host - > device . parent , cmd - > sge_dma ,
2006-11-22 21:44:34 +01:00
sizeof ( cmd - > scatter_gather_element ) ,
2007-02-04 20:54:57 +01:00
DMA_TO_DEVICE ) ;
2006-11-02 21:16:08 +01:00
/* Grab SCSI command pointers and check status. */
2006-07-23 22:18:00 +02:00
/*
* FIXME : If the src field in the status is 1 , the ORB DMA must
* not be reused until status for a subsequent ORB is received .
*/
2006-11-02 21:16:08 +01:00
SCpnt = cmd - > Current_SCpnt ;
spin_lock_irqsave ( & lu - > cmd_orb_lock , flags ) ;
sbp2util_mark_command_completed ( lu , cmd ) ;
spin_unlock_irqrestore ( & lu - > cmd_orb_lock , flags ) ;
2005-04-16 15:20:36 -07:00
if ( SCpnt ) {
2006-08-14 18:51:00 +02:00
u32 h = sb - > ORB_offset_hi_misc ;
u32 r = STATUS_GET_RESP ( h ) ;
if ( r ! = RESP_STATUS_REQUEST_COMPLETE ) {
2006-11-02 21:16:08 +01:00
SBP2_INFO ( " resp 0x%x, sbp_status 0x%x " ,
2006-08-14 18:51:00 +02:00
r , STATUS_GET_SBP_STATUS ( h ) ) ;
2006-07-23 22:18:00 +02:00
scsi_status =
2006-08-14 18:51:00 +02:00
r = = RESP_STATUS_TRANSPORT_FAILURE ?
SBP2_SCSI_STATUS_BUSY :
2006-07-23 22:18:00 +02:00
SBP2_SCSI_STATUS_COMMAND_TERMINATED ;
2006-08-14 18:51:00 +02:00
}
2006-11-02 21:16:08 +01:00
2006-11-02 21:16:08 +01:00
if ( STATUS_GET_LEN ( h ) > 1 )
2006-07-23 22:16:00 +02:00
scsi_status = sbp2_status_to_sense_data (
( unchar * ) sb , SCpnt - > sense_buffer ) ;
2006-11-02 21:16:08 +01:00
2006-11-02 21:16:08 +01:00
if ( STATUS_TEST_DEAD ( h ) )
2006-11-02 21:16:08 +01:00
sbp2_agent_reset ( lu , 0 ) ;
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
/* Check here to see if there are no commands in-use. If there
2006-07-23 22:12:00 +02:00
* are none , we know that the fetch agent left the active state
* _and_ that we did not reactivate it yet . Therefore clear
* last_orb so that next time we write directly to the
* ORB_POINTER register . That way the fetch agent does not need
2006-11-02 21:16:08 +01:00
* to refetch the next_ORB . */
2006-11-02 21:16:08 +01:00
spin_lock_irqsave ( & lu - > cmd_orb_lock , flags ) ;
if ( list_empty ( & lu - > cmd_orb_inuse ) )
lu - > last_orb = NULL ;
spin_unlock_irqrestore ( & lu - > cmd_orb_lock , flags ) ;
2005-04-16 15:20:36 -07:00
} else {
2006-11-02 21:16:08 +01:00
/* It's probably status after a management request. */
2006-11-02 21:16:08 +01:00
if ( ( sb - > ORB_offset_lo = = lu - > reconnect_orb_dma ) | |
( sb - > ORB_offset_lo = = lu - > login_orb_dma ) | |
( sb - > ORB_offset_lo = = lu - > query_logins_orb_dma ) | |
( sb - > ORB_offset_lo = = lu - > logout_orb_dma ) ) {
lu - > access_complete = 1 ;
2006-11-02 21:16:08 +01:00
wake_up_interruptible ( & sbp2_access_wq ) ;
2006-07-23 22:19:00 +02:00
}
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
if ( SCpnt )
2006-11-02 21:16:08 +01:00
sbp2scsi_complete_command ( lu , scsi_status , SCpnt ,
cmd - > Current_done ) ;
2005-11-07 06:31:39 -05:00
return RCODE_COMPLETE ;
2005-04-16 15:20:36 -07:00
}
/**************************************
* SCSI interface related section
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int sbp2scsi_queuecommand ( struct scsi_cmnd * SCpnt ,
void ( * done ) ( struct scsi_cmnd * ) )
{
2006-11-02 21:16:08 +01:00
struct sbp2_lu * lu = ( struct sbp2_lu * ) SCpnt - > device - > host - > hostdata [ 0 ] ;
2006-11-02 21:16:08 +01:00
struct sbp2_fwhost_info * hi ;
2005-09-30 11:59:06 -07:00
int result = DID_NO_CONNECT < < 16 ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
if ( unlikely ( ! sbp2util_node_is_available ( lu ) ) )
2005-09-30 11:59:06 -07:00
goto done ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
hi = lu - > hi ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
if ( unlikely ( ! hi ) ) {
2006-11-02 21:16:08 +01:00
SBP2_ERR ( " sbp2_fwhost_info is NULL - this is bad! " ) ;
2005-09-30 11:59:06 -07:00
goto done ;
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
/* Multiple units are currently represented to the SCSI core as separate
* targets , not as one target with multiple LUs . Therefore return
* selection time - out to any IO directed at non - zero LUNs . */
2006-11-02 21:16:08 +01:00
if ( unlikely ( SCpnt - > device - > lun ) )
2005-09-30 11:59:06 -07:00
goto done ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
if ( unlikely ( ! hpsb_node_entry_valid ( lu - > ne ) ) ) {
2005-04-16 15:20:36 -07:00
SBP2_ERR ( " Bus reset in progress - rejecting command " ) ;
2005-09-30 11:59:06 -07:00
result = DID_BUS_BUSY < < 16 ;
goto done ;
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
/* Bidirectional commands are not yet implemented,
* and unknown transfer direction not handled . */
2006-11-02 21:16:08 +01:00
if ( unlikely ( SCpnt - > sc_data_direction = = DMA_BIDIRECTIONAL ) ) {
2005-12-12 23:03:24 -05:00
SBP2_ERR ( " Cannot handle DMA_BIDIRECTIONAL - rejecting command " ) ;
result = DID_ERROR < < 16 ;
goto done ;
}
2006-11-02 21:16:08 +01:00
if ( sbp2_send_command ( lu , SCpnt , done ) ) {
2005-04-16 15:20:36 -07:00
SBP2_ERR ( " Error sending SCSI command " ) ;
2006-11-02 21:16:08 +01:00
sbp2scsi_complete_command ( lu ,
SBP2_SCSI_STATUS_SELECTION_TIMEOUT ,
2005-04-16 15:20:36 -07:00
SCpnt , done ) ;
}
2005-09-30 11:59:06 -07:00
return 0 ;
2005-04-16 15:20:36 -07:00
2005-09-30 11:59:06 -07:00
done :
SCpnt - > result = result ;
done ( SCpnt ) ;
return 0 ;
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
static void sbp2scsi_complete_all_commands ( struct sbp2_lu * lu , u32 status )
2005-04-16 15:20:36 -07:00
{
2006-11-02 21:16:08 +01:00
struct sbp2_fwhost_info * hi = lu - > hi ;
2005-04-16 15:20:36 -07:00
struct list_head * lh ;
2006-11-02 21:16:08 +01:00
struct sbp2_command_info * cmd ;
2005-11-07 06:29:39 -05:00
unsigned long flags ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
spin_lock_irqsave ( & lu - > cmd_orb_lock , flags ) ;
while ( ! list_empty ( & lu - > cmd_orb_inuse ) ) {
lh = lu - > cmd_orb_inuse . next ;
cmd = list_entry ( lh , struct sbp2_command_info , list ) ;
2006-12-29 23:47:04 +01:00
dma_sync_single_for_cpu ( hi - > host - > device . parent ,
cmd - > command_orb_dma ,
2006-11-22 21:44:34 +01:00
sizeof ( struct sbp2_command_orb ) ,
DMA_TO_DEVICE ) ;
2006-12-29 23:47:04 +01:00
dma_sync_single_for_cpu ( hi - > host - > device . parent , cmd - > sge_dma ,
2006-11-22 21:44:34 +01:00
sizeof ( cmd - > scatter_gather_element ) ,
2007-02-04 20:54:57 +01:00
DMA_TO_DEVICE ) ;
2006-11-02 21:16:08 +01:00
sbp2util_mark_command_completed ( lu , cmd ) ;
if ( cmd - > Current_SCpnt ) {
cmd - > Current_SCpnt - > result = status < < 16 ;
cmd - > Current_done ( cmd - > Current_SCpnt ) ;
2005-04-16 15:20:36 -07:00
}
}
2006-11-02 21:16:08 +01:00
spin_unlock_irqrestore ( & lu - > cmd_orb_lock , flags ) ;
2005-04-16 15:20:36 -07:00
return ;
}
/*
2006-11-02 21:16:08 +01:00
* Complete a regular SCSI command . Can be called in atomic context .
2005-04-16 15:20:36 -07:00
*/
2006-11-02 21:16:08 +01:00
static void sbp2scsi_complete_command ( struct sbp2_lu * lu , u32 scsi_status ,
struct scsi_cmnd * SCpnt ,
2005-04-16 15:20:36 -07:00
void ( * done ) ( struct scsi_cmnd * ) )
{
if ( ! SCpnt ) {
SBP2_ERR ( " SCpnt is NULL " ) ;
return ;
}
switch ( scsi_status ) {
2005-11-07 06:31:39 -05:00
case SBP2_SCSI_STATUS_GOOD :
2006-03-28 20:03:45 -05:00
SCpnt - > result = DID_OK < < 16 ;
2005-11-07 06:31:39 -05:00
break ;
2005-04-16 15:20:36 -07:00
2005-11-07 06:31:39 -05:00
case SBP2_SCSI_STATUS_BUSY :
SBP2_ERR ( " SBP2_SCSI_STATUS_BUSY " ) ;
SCpnt - > result = DID_BUS_BUSY < < 16 ;
break ;
2005-04-16 15:20:36 -07:00
2005-11-07 06:31:39 -05:00
case SBP2_SCSI_STATUS_CHECK_CONDITION :
2006-03-28 20:03:45 -05:00
SCpnt - > result = CHECK_CONDITION < < 1 | DID_OK < < 16 ;
2005-11-07 06:31:39 -05:00
break ;
2005-04-16 15:20:36 -07:00
2005-11-07 06:31:39 -05:00
case SBP2_SCSI_STATUS_SELECTION_TIMEOUT :
SBP2_ERR ( " SBP2_SCSI_STATUS_SELECTION_TIMEOUT " ) ;
SCpnt - > result = DID_NO_CONNECT < < 16 ;
scsi_print_command ( SCpnt ) ;
break ;
2005-04-16 15:20:36 -07:00
2005-11-07 06:31:39 -05:00
case SBP2_SCSI_STATUS_CONDITION_MET :
case SBP2_SCSI_STATUS_RESERVATION_CONFLICT :
case SBP2_SCSI_STATUS_COMMAND_TERMINATED :
SBP2_ERR ( " Bad SCSI status = %x " , scsi_status ) ;
SCpnt - > result = DID_ERROR < < 16 ;
scsi_print_command ( SCpnt ) ;
break ;
2005-04-16 15:20:36 -07:00
2005-11-07 06:31:39 -05:00
default :
SBP2_ERR ( " Unsupported SCSI status = %x " , scsi_status ) ;
SCpnt - > result = DID_ERROR < < 16 ;
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
/* If a bus reset is in progress and there was an error, complete
* the command as busy so that it will get retried . */
2006-11-02 21:16:08 +01:00
if ( ! hpsb_node_entry_valid ( lu - > ne )
2005-11-07 06:31:39 -05:00
& & ( scsi_status ! = SBP2_SCSI_STATUS_GOOD ) ) {
2005-04-16 15:20:36 -07:00
SBP2_ERR ( " Completing command with busy (bus reset) " ) ;
SCpnt - > result = DID_BUS_BUSY < < 16 ;
}
2006-11-02 21:16:08 +01:00
/* Tell the SCSI stack that we're done with this command. */
2005-11-07 06:31:39 -05:00
done ( SCpnt ) ;
2005-04-16 15:20:36 -07:00
}
2005-09-30 11:59:06 -07:00
static int sbp2scsi_slave_alloc ( struct scsi_device * sdev )
2005-04-16 15:20:36 -07:00
{
2006-11-02 21:16:08 +01:00
struct sbp2_lu * lu = ( struct sbp2_lu * ) sdev - > host - > hostdata [ 0 ] ;
2006-02-14 22:04:19 -05:00
2008-02-17 14:57:10 +01:00
if ( sdev - > lun ! = 0 | | sdev - > id ! = lu - > ud - > id | | sdev - > channel ! = 0 )
return - ENODEV ;
2006-11-02 21:16:08 +01:00
lu - > sdev = sdev ;
2006-08-07 20:48:00 +02:00
sdev - > allow_restart = 1 ;
2006-02-14 22:04:19 -05:00
2008-01-27 22:32:22 +01:00
/* SBP-2 requires quadlet alignment of the data buffers. */
blk_queue_update_dma_alignment ( sdev - > request_queue , 4 - 1 ) ;
2008-01-01 10:00:10 -06:00
2006-11-02 21:16:08 +01:00
if ( lu - > workarounds & SBP2_WORKAROUND_INQUIRY_36 )
2006-02-14 22:04:19 -05:00
sdev - > inquiry_len = 36 ;
2005-09-30 11:59:06 -07:00
return 0 ;
}
static int sbp2scsi_slave_configure ( struct scsi_device * sdev )
{
2006-11-02 21:16:08 +01:00
struct sbp2_lu * lu = ( struct sbp2_lu * ) sdev - > host - > hostdata [ 0 ] ;
2006-05-15 22:04:59 +02:00
2005-11-07 06:31:24 -05:00
sdev - > use_10_for_rw = 1 ;
2006-05-15 22:04:59 +02:00
2007-01-10 20:17:15 +01:00
if ( sdev - > type = = TYPE_ROM )
sdev - > use_10_for_ms = 1 ;
2006-05-15 22:04:59 +02:00
if ( sdev - > type = = TYPE_DISK & &
2006-11-02 21:16:08 +01:00
lu - > workarounds & SBP2_WORKAROUND_MODE_SENSE_8 )
2006-05-15 22:04:59 +02:00
sdev - > skip_ms_page_8 = 1 ;
2006-11-02 21:16:08 +01:00
if ( lu - > workarounds & SBP2_WORKAROUND_FIX_CAPACITY )
2006-05-15 22:06:37 +02:00
sdev - > fix_capacity = 1 ;
2007-12-16 17:31:26 +01:00
if ( lu - > workarounds & SBP2_WORKAROUND_128K_MAX_TRANS )
blk_queue_max_sectors ( sdev - > request_queue , 128 * 1024 / 512 ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
}
2005-09-30 11:59:06 -07:00
static void sbp2scsi_slave_destroy ( struct scsi_device * sdev )
{
2006-11-02 21:16:08 +01:00
( ( struct sbp2_lu * ) sdev - > host - > hostdata [ 0 ] ) - > sdev = NULL ;
2005-09-30 11:59:06 -07:00
return ;
}
2005-04-16 15:20:36 -07:00
/*
2006-11-02 21:16:08 +01:00
* Called by scsi stack when something has really gone wrong .
* Usually called when a command has timed - out for some reason .
2005-04-16 15:20:36 -07:00
*/
static int sbp2scsi_abort ( struct scsi_cmnd * SCpnt )
{
2006-11-02 21:16:08 +01:00
struct sbp2_lu * lu = ( struct sbp2_lu * ) SCpnt - > device - > host - > hostdata [ 0 ] ;
struct sbp2_fwhost_info * hi = lu - > hi ;
struct sbp2_command_info * cmd ;
2006-04-01 21:11:41 +02:00
unsigned long flags ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
SBP2_INFO ( " aborting sbp2 command " ) ;
2005-04-16 15:20:36 -07:00
scsi_print_command ( SCpnt ) ;
2006-11-02 21:16:08 +01:00
if ( sbp2util_node_is_available ( lu ) ) {
sbp2_agent_reset ( lu , 1 ) ;
2005-04-16 15:20:36 -07:00
2006-09-11 20:17:14 +02:00
/* Return a matching command structure to the free pool. */
2006-11-02 21:16:08 +01:00
spin_lock_irqsave ( & lu - > cmd_orb_lock , flags ) ;
cmd = sbp2util_find_command_for_SCpnt ( lu , SCpnt ) ;
if ( cmd ) {
2006-12-29 23:47:04 +01:00
dma_sync_single_for_cpu ( hi - > host - > device . parent ,
2006-11-02 21:16:08 +01:00
cmd - > command_orb_dma ,
sizeof ( struct sbp2_command_orb ) ,
2006-11-22 21:44:34 +01:00
DMA_TO_DEVICE ) ;
2006-12-29 23:47:04 +01:00
dma_sync_single_for_cpu ( hi - > host - > device . parent ,
cmd - > sge_dma ,
2006-11-02 21:16:08 +01:00
sizeof ( cmd - > scatter_gather_element ) ,
2007-02-04 20:54:57 +01:00
DMA_TO_DEVICE ) ;
2006-11-02 21:16:08 +01:00
sbp2util_mark_command_completed ( lu , cmd ) ;
if ( cmd - > Current_SCpnt ) {
cmd - > Current_SCpnt - > result = DID_ABORT < < 16 ;
cmd - > Current_done ( cmd - > Current_SCpnt ) ;
2005-04-16 15:20:36 -07:00
}
}
2006-11-02 21:16:08 +01:00
spin_unlock_irqrestore ( & lu - > cmd_orb_lock , flags ) ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
sbp2scsi_complete_all_commands ( lu , DID_BUS_BUSY ) ;
2005-04-16 15:20:36 -07:00
}
2005-11-07 06:31:39 -05:00
return SUCCESS ;
2005-04-16 15:20:36 -07:00
}
/*
* Called by scsi stack when something has really gone wrong .
*/
2005-09-30 11:59:06 -07:00
static int sbp2scsi_reset ( struct scsi_cmnd * SCpnt )
2005-04-16 15:20:36 -07:00
{
2006-11-02 21:16:08 +01:00
struct sbp2_lu * lu = ( struct sbp2_lu * ) SCpnt - > device - > host - > hostdata [ 0 ] ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
SBP2_INFO ( " reset requested " ) ;
2005-04-16 15:20:36 -07:00
2006-11-02 21:16:08 +01:00
if ( sbp2util_node_is_available ( lu ) ) {
2006-11-02 21:16:08 +01:00
SBP2_INFO ( " generating sbp2 fetch agent reset " ) ;
2006-11-02 21:16:08 +01:00
sbp2_agent_reset ( lu , 1 ) ;
2005-04-16 15:20:36 -07:00
}
2005-09-30 11:59:06 -07:00
return SUCCESS ;
2005-05-28 07:55:48 -04:00
}
2005-11-07 06:31:39 -05:00
static ssize_t sbp2_sysfs_ieee1394_id_show ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
2005-04-16 15:20:36 -07:00
{
struct scsi_device * sdev ;
2006-11-02 21:16:08 +01:00
struct sbp2_lu * lu ;
2005-04-16 15:20:36 -07:00
if ( ! ( sdev = to_scsi_device ( dev ) ) )
return 0 ;
2006-11-02 21:16:08 +01:00
if ( ! ( lu = ( struct sbp2_lu * ) sdev - > host - > hostdata [ 0 ] ) )
2005-04-16 15:20:36 -07:00
return 0 ;
2007-05-27 13:17:15 +02:00
if ( sbp2_long_sysfs_ieee1394_id )
return sprintf ( buf , " %016Lx:%06x:%04x \n " ,
( unsigned long long ) lu - > ne - > guid ,
lu - > ud - > directory_id , ORB_SET_LUN ( lu - > lun ) ) ;
else
return sprintf ( buf , " %016Lx:%d:%d \n " ,
( unsigned long long ) lu - > ne - > guid ,
lu - > ud - > id , ORB_SET_LUN ( lu - > lun ) ) ;
2005-04-16 15:20:36 -07:00
}
MODULE_AUTHOR ( " Ben Collins <bcollins@debian.org> " ) ;
MODULE_DESCRIPTION ( " IEEE-1394 SBP-2 protocol driver " ) ;
MODULE_SUPPORTED_DEVICE ( SBP2_DEVICE_NAME ) ;
MODULE_LICENSE ( " GPL " ) ;
static int sbp2_module_init ( void )
{
int ret ;
2006-11-02 21:16:08 +01:00
if ( sbp2_serialize_io ) {
sbp2_shost_template . can_queue = 1 ;
sbp2_shost_template . cmd_per_lun = 1 ;
2005-04-16 15:20:36 -07:00
}
2006-11-02 21:16:08 +01:00
sbp2_shost_template . max_sectors = sbp2_max_sectors ;
2005-04-16 15:20:36 -07:00
hpsb_register_highlevel ( & sbp2_highlevel ) ;
ret = hpsb_register_protocol ( & sbp2_driver ) ;
if ( ret ) {
SBP2_ERR ( " Failed to register protocol " ) ;
hpsb_unregister_highlevel ( & sbp2_highlevel ) ;
return ret ;
}
return 0 ;
}
static void __exit sbp2_module_exit ( void )
{
hpsb_unregister_protocol ( & sbp2_driver ) ;
hpsb_unregister_highlevel ( & sbp2_highlevel ) ;
}
module_init ( sbp2_module_init ) ;
module_exit ( sbp2_module_exit ) ;