2005-04-17 02:20:36 +04: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 23:16:08 +03: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-17 02:20:36 +04:00
*
2006-11-02 23:16:08 +03: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-17 02:20:36 +04:00
*
2006-11-02 23:16:08 +03: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-17 02:20:36 +04:00
*/
2007-12-16 19:31:26 +03:00
# include <linux/blkdev.h>
2006-08-14 20:56:00 +04:00
# include <linux/compiler.h>
# include <linux/delay.h>
# include <linux/device.h>
# include <linux/dma-mapping.h>
# include <linux/init.h>
2005-04-17 02:20:36 +04:00
# include <linux/kernel.h>
# include <linux/list.h>
2007-04-23 22:50:56 +04:00
# include <linux/mm.h>
2005-04-17 02:20:36 +04:00
# include <linux/module.h>
# include <linux/moduleparam.h>
2007-04-23 22:50:56 +04:00
# include <linux/sched.h>
2006-08-14 20:56:00 +04: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-24 00:19:00 +04:00
# include <linux/wait.h>
2007-05-05 19:18:12 +04:00
# include <linux/workqueue.h>
2007-10-30 12:35:04 +03:00
# include <linux/scatterlist.h>
2005-04-17 02:20:36 +04:00
# include <asm/byteorder.h>
2006-08-14 20:56:00 +04: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-17 02:20:36 +04: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 20:56:00 +04:00
# include "highlevel.h"
# include "hosts.h"
2005-04-17 02:20:36 +04:00
# include "ieee1394.h"
# include "ieee1394_core.h"
2006-08-14 20:56:00 +04:00
# include "ieee1394_hotplug.h"
2005-04-17 02:20:36 +04:00
# include "ieee1394_transactions.h"
2006-08-14 20:56:00 +04:00
# include "ieee1394_types.h"
# include "nodemgr.h"
2005-04-17 02:20:36 +04: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 23:16:08 +03:00
static int sbp2_max_speed = IEEE1394_SPEED_MAX ;
module_param_named ( max_speed , sbp2_max_speed , int , 0644 ) ;
2009-01-19 21:20:31 +03:00
MODULE_PARM_DESC ( max_speed , " Limit data transfer speed (5 <= 3200, "
" 4 <= 1600, 3 <= 800, 2 <= 400, 1 <= 200, 0 = 100 Mb/s) " ) ;
2005-04-17 02:20:36 +04:00
/*
2007-06-18 01:54:52 +04: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-17 02:20:36 +04:00
*/
2006-11-02 23:16:08 +03:00
static int sbp2_serialize_io = 1 ;
2007-06-18 01:54:52 +04: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-17 02:20:36 +04:00
/*
2007-12-16 19:31:26 +03: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-17 02:20:36 +04:00
*/
2007-12-16 19:31:26 +03:00
static int sbp2_max_sectors ;
2006-11-02 23:16:08 +03: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 19:31:26 +03:00
" (default = 0 = use SCSI stack's default) " ) ;
2005-04-17 02:20:36 +04: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-13 02: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-17 02:20:36 +04:00
*/
2006-11-02 23:16:08 +03:00
static int sbp2_exclusive_login = 1 ;
2007-06-18 01:54:52 +04:00
module_param_named ( exclusive_login , sbp2_exclusive_login , bool , 0644 ) ;
2006-11-02 23:16:08 +03:00
MODULE_PARM_DESC ( exclusive_login , " Exclusive login to sbp2 device "
2007-06-18 01:54:52 +04:00
" (default = Y, use N for concurrent initiators) " ) ;
2005-04-17 02:20:36 +04:00
/*
2006-05-16 00:04:59 +04: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-17 02:20:36 +04:00
*
2006-05-16 00:04:59 +04: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-16 00:06:37 +04: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-16 00:08:09 +04:00
*
2008-02-04 01:07:44 +03:00
* - delay inquiry
* Wait extra SBP2_INQUIRY_DELAY seconds after login before SCSI inquiry .
*
2008-05-11 02:35:55 +04:00
* - power condition
* Set the power condition field in the START STOP UNIT commands sent by
* sd_mod on suspend , resume , and shutdown ( if manage_start_stop is on ) .
* Some disks need this to spin down or to resume properly .
*
2006-05-16 00:08:09 +04:00
* - override internal blacklist
* Instead of adding to the built - in blacklist , use only the workarounds
* specified in the module load parameter .
* Useful if a blacklist entry interfered with a non - broken device .
2005-04-17 02:20:36 +04:00
*/
2006-05-16 00:04:59 +04: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-16 00:06:37 +04:00
" , fix capacity = " __stringify ( SBP2_WORKAROUND_FIX_CAPACITY )
2008-02-04 01:07:44 +03:00
" , delay inquiry = " __stringify ( SBP2_WORKAROUND_DELAY_INQUIRY )
2008-05-11 02:35:55 +04:00
" , set power condition in start stop unit = "
__stringify ( SBP2_WORKAROUND_POWER_CONDITION )
2006-05-16 00:08:09 +04:00
" , override internal blacklist = " __stringify ( SBP2_WORKAROUND_OVERRIDE )
2006-05-16 00:04:59 +04:00
" , or a combination) " ) ;
2007-05-27 15:17:15 +04: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-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
# define SBP2_INFO(fmt, args...) HPSB_INFO("sbp2: "fmt, ## args)
# define SBP2_ERR(fmt, args...) HPSB_ERR("sbp2: "fmt, ## args)
2005-04-17 02:20:36 +04:00
/*
* Globals
*/
2006-11-02 23:16:08 +03: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 23:16:08 +03:00
void ( * ) ( struct scsi_cmnd * ) ) ;
2006-11-02 23:16:08 +03: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 23:16:08 +03: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 23:16:08 +03:00
static int sbp2_agent_reset ( struct sbp2_lu * , int ) ;
static void sbp2_parse_unit_directory ( struct sbp2_lu * ,
2006-11-02 23:16:08 +03:00
struct unit_directory * ) ;
2006-11-02 23:16:08 +03:00
static int sbp2_set_busy_timeout ( struct sbp2_lu * ) ;
static int sbp2_max_speed_and_size ( struct sbp2_lu * ) ;
2005-04-17 02:20:36 +04:00
2009-01-24 21:41:46 +03:00
static const u8 sbp2_speedto_max_payload [ ] = { 0x7 , 0x8 , 0x9 , 0xa , 0xa , 0xa } ;
2005-04-17 02:20:36 +04:00
2007-08-11 13:52:08 +04:00
static DEFINE_RWLOCK ( sbp2_hi_logical_units_lock ) ;
2005-04-17 02:20:36 +04:00
static struct hpsb_highlevel sbp2_highlevel = {
2006-11-02 23:16:08 +03:00
. name = SBP2_DEVICE_NAME ,
. host_reset = sbp2_host_reset ,
2005-04-17 02:20:36 +04:00
} ;
2009-02-10 00:05:06 +03:00
static const struct hpsb_address_ops sbp2_ops = {
2006-11-02 23:16:08 +03:00
. write = sbp2_handle_status_write
2005-04-17 02:20:36 +04:00
} ;
# ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
2006-11-02 23:16:08 +03: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 ) ;
2009-02-10 00:05:06 +03:00
static const struct hpsb_address_ops sbp2_physdma_ops = {
2006-11-02 23:16:08 +03:00
. read = sbp2_handle_physdma_read ,
. write = sbp2_handle_physdma_write ,
2005-04-17 02:20:36 +04:00
} ;
# endif
2006-11-02 23:16:08 +03:00
/*
* Interface to driver core and IEEE 1394 core
*/
2009-02-16 01:11:38 +03:00
static const struct ieee1394_device_id sbp2_id_table [ ] = {
2006-11-02 23:16:08 +03:00
{
. 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-17 02:20:36 +04:00
static struct hpsb_protocol_driver sbp2_driver = {
2006-11-23 21:59:48 +03:00
. name = SBP2_DEVICE_NAME ,
2005-04-17 02:20:36 +04:00
. id_table = sbp2_id_table ,
. update = sbp2_update ,
. driver = {
. probe = sbp2_probe ,
. remove = sbp2_remove ,
} ,
} ;
2006-11-02 23:16:08 +03: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 23:16:08 +03:00
static struct scsi_host_template sbp2_shost_template = {
2006-11-02 23:16:08 +03: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 ,
} ;
2009-01-24 21:41:46 +03:00
# define SBP2_ROM_VALUE_WILDCARD ~0 /* match all */
# define SBP2_ROM_VALUE_MISSING 0xff000000 /* not present in the unit dir. */
2006-11-02 23:16:08 +03:00
2006-02-15 06:04:19 +03:00
/*
2006-05-16 00:04:59 +04: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-15 06:04:19 +03:00
*/
2006-05-16 00:04:59 +04:00
static const struct {
u32 firmware_revision ;
2009-01-24 21:41:46 +03:00
u32 model ;
2006-05-16 00:04:59 +04:00
unsigned workarounds ;
} sbp2_workarounds_table [ ] = {
2006-06-13 02:10:18 +04:00
/* DViCO Momobay CX-1 with TSB42AA9 bridge */ {
2006-05-16 00:04:59 +04:00
. firmware_revision = 0x002800 ,
2009-01-24 21:41:46 +03:00
. model = 0x001010 ,
2006-05-16 00:04:59 +04:00
. workarounds = SBP2_WORKAROUND_INQUIRY_36 |
2008-05-11 02:35:55 +04:00
SBP2_WORKAROUND_MODE_SENSE_8 |
SBP2_WORKAROUND_POWER_CONDITION ,
2006-05-16 00:04:59 +04:00
} ,
2008-02-04 01:07:44 +03:00
/* DViCO Momobay FX-3A with TSB42AA9A bridge */ {
. firmware_revision = 0x002800 ,
2009-01-24 21:41:46 +03:00
. model = 0x000000 ,
2009-09-06 21:34:17 +04:00
. workarounds = SBP2_WORKAROUND_POWER_CONDITION ,
2008-02-04 01:07:44 +03:00
} ,
2006-05-16 00:04:59 +04:00
/* Initio bridges, actually only needed for some older ones */ {
. firmware_revision = 0x000200 ,
2009-01-24 21:41:46 +03:00
. model = SBP2_ROM_VALUE_WILDCARD ,
2006-05-16 00:04:59 +04:00
. workarounds = SBP2_WORKAROUND_INQUIRY_36 ,
} ,
2008-05-11 02:35:55 +04:00
/* PL-3507 bridge with Prolific firmware */ {
. firmware_revision = 0x012800 ,
2009-01-24 21:41:46 +03:00
. model = SBP2_ROM_VALUE_WILDCARD ,
2008-05-11 02:35:55 +04:00
. workarounds = SBP2_WORKAROUND_POWER_CONDITION ,
} ,
2006-05-16 00:04:59 +04:00
/* Symbios bridge */ {
. firmware_revision = 0xa0b800 ,
2009-01-24 21:41:46 +03:00
. model = SBP2_ROM_VALUE_WILDCARD ,
2006-05-16 00:04:59 +04:00
. workarounds = SBP2_WORKAROUND_128K_MAX_TRANS ,
2006-05-16 00:06:37 +04:00
} ,
2008-03-12 00:32:52 +03:00
/* Datafab MD2-FW2 with Symbios/LSILogic SYM13FW500 bridge */ {
. firmware_revision = 0x002600 ,
2009-01-24 21:41:46 +03:00
. model = SBP2_ROM_VALUE_WILDCARD ,
2008-03-12 00:32:52 +03:00
. workarounds = SBP2_WORKAROUND_128K_MAX_TRANS ,
} ,
2009-01-29 02:13:20 +03:00
/*
* iPod 2 nd generation : needs 128 k max transfer size workaround
* iPod 3 rd generation : needs fix capacity workaround
*/
{
. firmware_revision = 0x0a2700 ,
. model = 0x000000 ,
. workarounds = SBP2_WORKAROUND_128K_MAX_TRANS |
SBP2_WORKAROUND_FIX_CAPACITY ,
} ,
2006-05-16 00:06:37 +04:00
/* iPod 4th generation */ {
. firmware_revision = 0x0a2700 ,
2009-01-24 21:41:46 +03:00
. model = 0x000021 ,
2006-05-16 00:06:37 +04:00
. workarounds = SBP2_WORKAROUND_FIX_CAPACITY ,
} ,
2008-11-22 14:38:24 +03:00
/* iPod mini */ {
. firmware_revision = 0x0a2700 ,
2009-01-24 21:41:46 +03:00
. model = 0x000022 ,
2008-11-22 14:38:24 +03:00
. workarounds = SBP2_WORKAROUND_FIX_CAPACITY ,
} ,
2006-05-16 00:06:37 +04:00
/* iPod mini */ {
. firmware_revision = 0x0a2700 ,
2009-01-24 21:41:46 +03:00
. model = 0x000023 ,
2006-05-16 00:06:37 +04:00
. workarounds = SBP2_WORKAROUND_FIX_CAPACITY ,
} ,
/* iPod Photo */ {
. firmware_revision = 0x0a2700 ,
2009-01-24 21:41:46 +03:00
. model = 0x00007e ,
2006-05-16 00:06:37 +04:00
. workarounds = SBP2_WORKAROUND_FIX_CAPACITY ,
2006-05-16 00:04:59 +04:00
}
2005-04-17 02:20:36 +04:00
} ;
/**************************************
* General utility functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifndef __BIG_ENDIAN
/*
* Converts a buffer from be32 to cpu byte ordering . Length is in bytes .
*/
2006-07-03 20:02:28 +04:00
static inline void sbp2util_be32_to_cpu_buffer ( void * buffer , int length )
2005-04-17 02:20:36 +04: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 20:02:28 +04:00
static inline void sbp2util_cpu_to_be32_buffer ( void * buffer , int length )
2005-04-17 02:20:36 +04: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 20:44:00 +04: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-17 02:20:36 +04:00
# endif
2006-11-02 23:16:08 +03:00
static DECLARE_WAIT_QUEUE_HEAD ( sbp2_access_wq ) ;
2006-07-24 00:19:00 +04:00
2005-04-17 02:20:36 +04:00
/*
2006-07-24 00:19:00 +04:00
* Waits for completion of an SBP - 2 access request .
* Returns nonzero if timed out or prematurely interrupted .
2005-04-17 02:20:36 +04:00
*/
2006-11-02 23:16:08 +03:00
static int sbp2util_access_timeout ( struct sbp2_lu * lu , int timeout )
2005-04-17 02:20:36 +04:00
{
2006-11-02 23:16:08 +03:00
long leftover ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
leftover = wait_event_interruptible_timeout (
2006-11-02 23:16:08 +03:00
sbp2_access_wq , lu - > access_complete , timeout ) ;
lu - > access_complete = 0 ;
2006-07-24 00:19:00 +04:00
return leftover < = 0 ;
2005-04-17 02:20:36 +04:00
}
2006-11-02 23:16:08 +03:00
static void sbp2_free_packet ( void * packet )
2005-04-17 02:20:36 +04:00
{
hpsb_free_tlabel ( packet ) ;
hpsb_free_packet ( packet ) ;
}
2006-11-02 23:16:08 +03: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-17 02:20:36 +04:00
*/
static int sbp2util_node_write_no_wait ( struct node_entry * ne , u64 addr ,
2006-11-02 23:16:08 +03:00
quadlet_t * buf , size_t len )
2005-04-17 02:20:36 +04:00
{
struct hpsb_packet * packet ;
2006-11-02 23:16:08 +03:00
packet = hpsb_make_writepacket ( ne - > host , ne - > nodeid , addr , buf , len ) ;
2005-11-07 14:31:39 +03:00
if ( ! packet )
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
hpsb_set_packet_complete_task ( packet , sbp2_free_packet , packet ) ;
2005-04-17 02:20:36 +04:00
hpsb_node_fill_packet ( ne , packet ) ;
2005-11-07 14:31:39 +03:00
if ( hpsb_send_packet ( packet ) < 0 ) {
2005-04-17 02:20:36 +04:00
sbp2_free_packet ( packet ) ;
return - EIO ;
}
return 0 ;
}
2006-11-02 23:16:08 +03:00
static void sbp2util_notify_fetch_agent ( struct sbp2_lu * lu , u64 offset ,
quadlet_t * data , size_t len )
2006-08-14 20:43:00 +04:00
{
2006-11-02 23:16:08 +03: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 20:43:00 +04:00
return ;
2006-11-02 23:16:08 +03:00
if ( hpsb_node_write ( lu - > ne , lu - > command_block_agent_addr + offset ,
2006-08-14 20:43:00 +04:00
data , len ) )
SBP2_ERR ( " sbp2util_notify_fetch_agent failed. " ) ;
2006-11-02 23:16:08 +03: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 20:43:00 +04:00
}
2006-11-22 17:57:56 +03:00
static void sbp2util_write_orb_pointer ( struct work_struct * work )
2006-08-14 20:43:00 +04:00
{
2006-12-08 01:23:25 +03:00
struct sbp2_lu * lu = container_of ( work , struct sbp2_lu , protocol_work ) ;
2006-08-14 20:43:00 +04:00
quadlet_t data [ 2 ] ;
2006-12-08 01:23:25 +03:00
data [ 0 ] = ORB_SET_NODE_ID ( lu - > hi - > host - > node_id ) ;
data [ 1 ] = lu - > last_orb_dma ;
2006-08-14 20:43:00 +04:00
sbp2util_cpu_to_be32_buffer ( data , 8 ) ;
2006-12-08 01:23:25 +03:00
sbp2util_notify_fetch_agent ( lu , SBP2_ORB_POINTER_OFFSET , data , 8 ) ;
2006-08-14 20:43:00 +04:00
}
2006-11-22 17:57:56 +03:00
static void sbp2util_write_doorbell ( struct work_struct * work )
2006-08-14 20:43:00 +04:00
{
2006-12-08 01:23:25 +03: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 20:43:00 +04:00
}
2006-11-02 23:16:08 +03:00
static int sbp2util_create_command_orb_pool ( struct sbp2_lu * lu )
2005-04-17 02:20:36 +04:00
{
2006-11-02 23:16:08 +03:00
struct sbp2_command_info * cmd ;
2008-08-09 22:16:24 +04:00
struct device * dmadev = lu - > hi - > host - > device . parent ;
2007-02-04 22:57:38 +03:00
int i , orbs = sbp2_serialize_io ? 2 : SBP2_MAX_CMDS ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < orbs ; i + + ) {
2007-02-04 22:57:38 +03:00
cmd = kzalloc ( sizeof ( * cmd ) , GFP_KERNEL ) ;
if ( ! cmd )
2008-08-09 22:16:24 +04:00
goto failed_alloc ;
cmd - > command_orb_dma =
dma_map_single ( dmadev , & cmd - > command_orb ,
sizeof ( struct sbp2_command_orb ) ,
DMA_TO_DEVICE ) ;
if ( dma_mapping_error ( dmadev , cmd - > command_orb_dma ) )
goto failed_orb ;
cmd - > sge_dma =
dma_map_single ( dmadev , & cmd - > scatter_gather_element ,
sizeof ( cmd - > scatter_gather_element ) ,
DMA_TO_DEVICE ) ;
if ( dma_mapping_error ( dmadev , cmd - > sge_dma ) )
goto failed_sge ;
2006-11-02 23:16:08 +03:00
INIT_LIST_HEAD ( & cmd - > list ) ;
list_add_tail ( & cmd - > list , & lu - > cmd_orb_completed ) ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
2008-08-09 22:16:24 +04:00
failed_sge :
dma_unmap_single ( dmadev , cmd - > command_orb_dma ,
sizeof ( struct sbp2_command_orb ) , DMA_TO_DEVICE ) ;
failed_orb :
kfree ( cmd ) ;
failed_alloc :
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
}
2007-08-11 13:51:16 +04:00
static void sbp2util_remove_command_orb_pool ( struct sbp2_lu * lu ,
struct hpsb_host * host )
2005-04-17 02:20:36 +04:00
{
struct list_head * lh , * next ;
2006-11-02 23:16:08 +03:00
struct sbp2_command_info * cmd ;
2005-04-17 02:20:36 +04:00
unsigned long flags ;
2006-11-02 23:16:08 +03: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-30 01:47:04 +03:00
dma_unmap_single ( host - > device . parent ,
cmd - > command_orb_dma ,
2005-04-17 02:20:36 +04:00
sizeof ( struct sbp2_command_orb ) ,
2006-11-22 23:44:34 +03:00
DMA_TO_DEVICE ) ;
2006-12-30 01:47:04 +03:00
dma_unmap_single ( host - > device . parent , cmd - > sge_dma ,
2006-11-02 23:16:08 +03:00
sizeof ( cmd - > scatter_gather_element ) ,
2007-02-04 22:54:57 +03:00
DMA_TO_DEVICE ) ;
2006-11-02 23:16:08 +03:00
kfree ( cmd ) ;
2005-04-17 02:20:36 +04:00
}
2006-11-02 23:16:08 +03:00
spin_unlock_irqrestore ( & lu - > cmd_orb_lock , flags ) ;
2005-04-17 02:20:36 +04:00
return ;
}
/*
2006-11-02 23:16:08 +03:00
* Finds the sbp2_command for a given outstanding command ORB .
* Only looks at the in - use list .
2005-04-17 02:20:36 +04:00
*/
static struct sbp2_command_info * sbp2util_find_command_for_orb (
2006-11-02 23:16:08 +03:00
struct sbp2_lu * lu , dma_addr_t orb )
2005-04-17 02:20:36 +04:00
{
2006-11-02 23:16:08 +03:00
struct sbp2_command_info * cmd ;
2005-04-17 02:20:36 +04:00
unsigned long flags ;
2006-11-02 23:16:08 +03: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-17 02:20:36 +04:00
}
2006-11-02 23:16:08 +03:00
spin_unlock_irqrestore ( & lu - > cmd_orb_lock , flags ) ;
2005-11-07 14:31:39 +03:00
return NULL ;
2005-04-17 02:20:36 +04:00
}
/*
2006-11-02 23:16:08 +03:00
* Finds the sbp2_command for a given outstanding SCpnt .
* Only looks at the in - use list .
2006-11-02 23:16:08 +03:00
* Must be called with lu - > cmd_orb_lock held .
2005-04-17 02:20:36 +04:00
*/
2006-04-01 23:11:41 +04:00
static struct sbp2_command_info * sbp2util_find_command_for_SCpnt (
2006-11-02 23:16:08 +03:00
struct sbp2_lu * lu , void * SCpnt )
2005-04-17 02:20:36 +04:00
{
2006-11-02 23:16:08 +03:00
struct sbp2_command_info * cmd ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03: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 14:31:39 +03:00
return NULL ;
2005-04-17 02:20:36 +04:00
}
static struct sbp2_command_info * sbp2util_allocate_command_orb (
2006-11-02 23:16:08 +03:00
struct sbp2_lu * lu ,
struct scsi_cmnd * Current_SCpnt ,
void ( * Current_done ) ( struct scsi_cmnd * ) )
2005-04-17 02:20:36 +04:00
{
struct list_head * lh ;
2006-11-02 23:16:08 +03:00
struct sbp2_command_info * cmd = NULL ;
2005-04-17 02:20:36 +04:00
unsigned long flags ;
2006-11-02 23:16:08 +03:00
spin_lock_irqsave ( & lu - > cmd_orb_lock , flags ) ;
if ( ! list_empty ( & lu - > cmd_orb_completed ) ) {
lh = lu - > cmd_orb_completed . next ;
2005-04-17 02:20:36 +04:00
list_del ( lh ) ;
2006-11-02 23:16:08 +03: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-06 05:24:54 +03:00
SBP2_ERR ( " %s: no orbs available " , __func__ ) ;
2006-11-02 23:16:08 +03:00
spin_unlock_irqrestore ( & lu - > cmd_orb_lock , flags ) ;
return cmd ;
2005-04-17 02:20:36 +04:00
}
2006-11-04 11:55:33 +03: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-17 02:20:36 +04:00
{
2008-08-14 11:28:14 +04:00
if ( scsi_sg_count ( cmd - > Current_SCpnt ) )
dma_unmap_sg ( lu - > ud - > ne - > host - > device . parent ,
scsi_sglist ( cmd - > Current_SCpnt ) ,
scsi_sg_count ( cmd - > Current_SCpnt ) ,
cmd - > Current_SCpnt - > sc_data_direction ) ;
2006-11-02 23:16:08 +03:00
list_move_tail ( & cmd - > list , & lu - > cmd_orb_completed ) ;
2005-04-17 02:20:36 +04:00
}
2005-09-30 22:59:06 +04:00
/*
2006-11-02 23:16:08 +03:00
* Is lu valid ? Is the 1394 node still present ?
2005-09-30 22:59:06 +04:00
*/
2006-11-02 23:16:08 +03:00
static inline int sbp2util_node_is_available ( struct sbp2_lu * lu )
2005-09-30 22:59:06 +04:00
{
2006-11-02 23:16:08 +03:00
return lu & & lu - > ne & & ! lu - > ne - > in_limbo ;
2005-09-30 22:59:06 +04:00
}
2005-04-17 02:20:36 +04:00
/*********************************************
* IEEE - 1394 core driver stack related section
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int sbp2_probe ( struct device * dev )
{
struct unit_directory * ud ;
2006-11-02 23:16:08 +03:00
struct sbp2_lu * lu ;
2005-04-17 02:20:36 +04: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 23:16:08 +03:00
lu = sbp2_alloc_device ( ud ) ;
if ( ! lu )
2005-11-07 14:31:39 +03:00
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
sbp2_parse_unit_directory ( lu , ud ) ;
return sbp2_start_device ( lu ) ;
2005-04-17 02:20:36 +04:00
}
static int sbp2_remove ( struct device * dev )
{
struct unit_directory * ud ;
2006-11-02 23:16:08 +03:00
struct sbp2_lu * lu ;
2005-09-30 22:59:06 +04:00
struct scsi_device * sdev ;
2005-04-17 02:20:36 +04:00
ud = container_of ( dev , struct unit_directory , device ) ;
2009-05-01 01:43:31 +04:00
lu = dev_get_drvdata ( & ud - > device ) ;
2006-11-02 23:16:08 +03:00
if ( ! lu )
2005-09-30 22:59:06 +04:00
return 0 ;
2006-11-02 23:16:08 +03:00
if ( lu - > shost ) {
2006-01-31 08:13:06 +03:00
/* Get rid of enqueued commands if there is no chance to
* send them . */
2006-11-02 23:16:08 +03:00
if ( ! sbp2util_node_is_available ( lu ) )
sbp2scsi_complete_all_commands ( lu , DID_NO_CONNECT ) ;
2006-11-02 23:16:08 +03:00
/* scsi_remove_device() may trigger shutdown functions of SCSI
2006-01-31 08:13:06 +03:00
* highlevel drivers which would deadlock if blocked . */
2006-11-02 23:16:08 +03:00
atomic_set ( & lu - > state , SBP2LU_STATE_IN_SHUTDOWN ) ;
scsi_unblock_requests ( lu - > shost ) ;
2006-01-31 08:13:06 +03:00
}
2006-11-02 23:16:08 +03:00
sdev = lu - > sdev ;
2005-09-30 22:59:06 +04:00
if ( sdev ) {
2006-11-02 23:16:08 +03:00
lu - > sdev = NULL ;
2005-09-30 22:59:06 +04:00
scsi_remove_device ( sdev ) ;
}
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
sbp2_logout_device ( lu ) ;
sbp2_remove_device ( lu ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int sbp2_update ( struct unit_directory * ud )
{
2009-05-01 01:43:31 +04:00
struct sbp2_lu * lu = dev_get_drvdata ( & ud - > device ) ;
2005-04-17 02:20:36 +04:00
2008-08-16 15:39:26 +04:00
if ( sbp2_reconnect_device ( lu ) ! = 0 ) {
/*
* Reconnect failed . If another bus reset happened ,
* let nodemgr proceed and call sbp2_update again later
* ( or sbp2_remove if this node went away ) .
*/
if ( ! hpsb_node_entry_valid ( lu - > ne ) )
return 0 ;
/*
* Or the target rejected the reconnect because we weren ' t
* fast enough . Try a regular login , but first log out
* just in case of any weirdness .
*/
2006-11-02 23:16:08 +03:00
sbp2_logout_device ( lu ) ;
2005-04-17 02:20:36 +04:00
2008-08-16 15:39:26 +04:00
if ( sbp2_login_device ( lu ) ! = 0 ) {
if ( ! hpsb_node_entry_valid ( lu - > ne ) )
return 0 ;
/* Maybe another initiator won the login. */
2005-04-17 02:20:36 +04:00
SBP2_ERR ( " Failed to reconnect to sbp2 device! " ) ;
return - EBUSY ;
}
}
2006-11-02 23:16:08 +03:00
sbp2_set_busy_timeout ( lu ) ;
sbp2_agent_reset ( lu , 1 ) ;
sbp2_max_speed_and_size ( lu ) ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
/* Complete any pending commands with busy (so they get retried)
* and remove them from our queue . */
2006-11-02 23:16:08 +03:00
sbp2scsi_complete_all_commands ( lu , DID_BUS_BUSY ) ;
2005-04-17 02:20:36 +04:00
2006-08-14 20:46:00 +04:00
/* Accept new commands unless there was another bus reset in the
* meantime . */
2006-11-02 23:16:08 +03:00
if ( hpsb_node_entry_valid ( lu - > ne ) ) {
atomic_set ( & lu - > state , SBP2LU_STATE_RUNNING ) ;
scsi_unblock_requests ( lu - > shost ) ;
2006-08-14 20:46:00 +04:00
}
2005-04-17 02:20:36 +04:00
return 0 ;
}
2006-11-02 23:16:08 +03:00
static struct sbp2_lu * sbp2_alloc_device ( struct unit_directory * ud )
2005-04-17 02:20:36 +04:00
{
2006-11-02 23:16:08 +03:00
struct sbp2_fwhost_info * hi ;
2006-11-02 23:16:08 +03:00
struct Scsi_Host * shost = NULL ;
struct sbp2_lu * lu = NULL ;
2007-08-11 13:52:08 +04:00
unsigned long flags ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
lu = kzalloc ( sizeof ( * lu ) , GFP_KERNEL ) ;
if ( ! lu ) {
SBP2_ERR ( " failed to create lu " ) ;
2005-04-17 02:20:36 +04:00
goto failed_alloc ;
}
2006-11-02 23:16:08 +03: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-17 02:20:36 +04:00
2009-05-01 01:43:31 +04:00
dev_set_drvdata ( & ud - > device , lu ) ;
2005-04-17 02:20:36 +04:00
hi = hpsb_get_hostinfo ( & sbp2_highlevel , ud - > ne - > host ) ;
if ( ! hi ) {
2006-11-02 23:16:08 +03:00
hi = hpsb_create_hostinfo ( & sbp2_highlevel , ud - > ne - > host ,
sizeof ( * hi ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! hi ) {
SBP2_ERR ( " failed to allocate hostinfo " ) ;
goto failed_alloc ;
}
hi - > host = ud - > ne - > host ;
2006-11-02 23:16:08 +03:00
INIT_LIST_HEAD ( & hi - > logical_units ) ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
/* Handle data movement if physical dma is not
2006-03-29 04:59:42 +04: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-17 02:20:36 +04:00
# endif
}
2008-08-14 11:28:14 +04:00
if ( dma_get_max_seg_size ( hi - > host - > device . parent ) > SBP2_MAX_SEG_SIZE )
BUG_ON ( dma_set_max_seg_size ( hi - > host - > device . parent ,
SBP2_MAX_SEG_SIZE ) ) ;
2006-03-29 04:54:52 +04: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 23:16:08 +03:00
lu - > hi = hi ;
2005-04-17 02:20:36 +04:00
2007-08-11 13:52:08 +04:00
write_lock_irqsave ( & sbp2_hi_logical_units_lock , flags ) ;
2006-11-02 23:16:08 +03:00
list_add_tail ( & lu - > lu_list , & hi - > logical_units ) ;
2007-08-11 13:52:08 +04:00
write_unlock_irqrestore ( & sbp2_hi_logical_units_lock , flags ) ;
2005-04-17 02:20:36 +04:00
2006-01-31 08:13:33 +03: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-16 00:09:46 +04: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 23:16:08 +03:00
lu - > status_fifo_addr = hpsb_allocate_and_register_addrspace (
2006-01-31 08:13:33 +03:00
& sbp2_highlevel , ud - > ne - > host , & sbp2_ops ,
sizeof ( struct sbp2_status_block ) , sizeof ( quadlet_t ) ,
2006-06-13 02:13:49 +04:00
ud - > ne - > host - > low_addr_space , CSR1212_ALL_SPACE_END ) ;
2006-11-02 23:16:08 +03:00
if ( lu - > status_fifo_addr = = CSR1212_INVALID_ADDR_SPACE ) {
2006-01-31 08:13:33 +03:00
SBP2_ERR ( " failed to allocate status FIFO address range " ) ;
goto failed_alloc ;
}
2006-11-02 23:16:08 +03:00
shost = scsi_host_alloc ( & sbp2_shost_template , sizeof ( unsigned long ) ) ;
if ( ! shost ) {
2005-04-17 02:20:36 +04:00
SBP2_ERR ( " failed to register scsi host " ) ;
goto failed_alloc ;
}
2006-11-02 23:16:08 +03:00
shost - > hostdata [ 0 ] = ( unsigned long ) lu ;
2009-06-30 22:28:31 +04:00
shost - > max_cmd_len = SBP2_MAX_CDB_SIZE ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
if ( ! scsi_add_host ( shost , & ud - > device ) ) {
lu - > shost = shost ;
return lu ;
2005-04-17 02:20:36 +04:00
}
SBP2_ERR ( " failed to add scsi host " ) ;
2006-11-02 23:16:08 +03:00
scsi_host_put ( shost ) ;
2005-04-17 02:20:36 +04:00
failed_alloc :
2006-11-02 23:16:08 +03:00
sbp2_remove_device ( lu ) ;
2005-04-17 02:20:36 +04:00
return NULL ;
}
static void sbp2_host_reset ( struct hpsb_host * host )
{
2006-11-02 23:16:08 +03:00
struct sbp2_fwhost_info * hi ;
2006-11-02 23:16:08 +03:00
struct sbp2_lu * lu ;
2007-08-11 13:52:08 +04:00
unsigned long flags ;
2005-04-17 02:20:36 +04:00
hi = hpsb_get_hostinfo ( & sbp2_highlevel , host ) ;
2006-08-14 20:59:00 +04:00
if ( ! hi )
return ;
2007-08-11 13:52:08 +04:00
read_lock_irqsave ( & sbp2_hi_logical_units_lock , flags ) ;
2008-11-29 16:55:47 +03:00
2006-11-02 23:16:08 +03:00
list_for_each_entry ( lu , & hi - > logical_units , lu_list )
2008-11-29 16:55:47 +03:00
if ( atomic_cmpxchg ( & lu - > state ,
SBP2LU_STATE_RUNNING , SBP2LU_STATE_IN_RESET )
= = SBP2LU_STATE_RUNNING )
2006-11-02 23:16:08 +03:00
scsi_block_requests ( lu - > shost ) ;
2008-11-29 16:55:47 +03:00
2007-08-11 13:52:08 +04:00
read_unlock_irqrestore ( & sbp2_hi_logical_units_lock , flags ) ;
2005-04-17 02:20:36 +04:00
}
2006-11-02 23:16:08 +03:00
static int sbp2_start_device ( struct sbp2_lu * lu )
2005-04-17 02:20:36 +04:00
{
2006-11-02 23:16:08 +03:00
struct sbp2_fwhost_info * hi = lu - > hi ;
2005-09-10 21:44:09 +04:00
int error ;
2005-04-17 02:20:36 +04:00
2006-12-30 01:47:04 +03:00
lu - > login_response = dma_alloc_coherent ( hi - > host - > device . parent ,
2005-11-07 14:31:39 +03:00
sizeof ( struct sbp2_login_response ) ,
2006-11-22 23:44:34 +03:00
& lu - > login_response_dma , GFP_KERNEL ) ;
2006-11-02 23:16:08 +03:00
if ( ! lu - > login_response )
2005-04-17 02:20:36 +04:00
goto alloc_fail ;
2006-12-30 01:47:04 +03:00
lu - > query_logins_orb = dma_alloc_coherent ( hi - > host - > device . parent ,
2005-11-07 14:31:39 +03:00
sizeof ( struct sbp2_query_logins_orb ) ,
2006-11-22 23:44:34 +03:00
& lu - > query_logins_orb_dma , GFP_KERNEL ) ;
2006-11-02 23:16:08 +03:00
if ( ! lu - > query_logins_orb )
2005-04-17 02:20:36 +04:00
goto alloc_fail ;
2006-12-30 01:47:04 +03:00
lu - > query_logins_response = dma_alloc_coherent ( hi - > host - > device . parent ,
2005-11-07 14:31:39 +03:00
sizeof ( struct sbp2_query_logins_response ) ,
2006-11-22 23:44:34 +03:00
& lu - > query_logins_response_dma , GFP_KERNEL ) ;
2006-11-02 23:16:08 +03:00
if ( ! lu - > query_logins_response )
2005-04-17 02:20:36 +04:00
goto alloc_fail ;
2006-12-30 01:47:04 +03:00
lu - > reconnect_orb = dma_alloc_coherent ( hi - > host - > device . parent ,
2005-11-07 14:31:39 +03:00
sizeof ( struct sbp2_reconnect_orb ) ,
2006-11-22 23:44:34 +03:00
& lu - > reconnect_orb_dma , GFP_KERNEL ) ;
2006-11-02 23:16:08 +03:00
if ( ! lu - > reconnect_orb )
2005-04-17 02:20:36 +04:00
goto alloc_fail ;
2006-12-30 01:47:04 +03:00
lu - > logout_orb = dma_alloc_coherent ( hi - > host - > device . parent ,
2005-11-07 14:31:39 +03:00
sizeof ( struct sbp2_logout_orb ) ,
2006-11-22 23:44:34 +03:00
& lu - > logout_orb_dma , GFP_KERNEL ) ;
2006-11-02 23:16:08 +03:00
if ( ! lu - > logout_orb )
2005-04-17 02:20:36 +04:00
goto alloc_fail ;
2006-12-30 01:47:04 +03:00
lu - > login_orb = dma_alloc_coherent ( hi - > host - > device . parent ,
2005-11-07 14:31:39 +03:00
sizeof ( struct sbp2_login_orb ) ,
2006-11-22 23:44:34 +03:00
& lu - > login_orb_dma , GFP_KERNEL ) ;
2006-11-02 23:16:08 +03:00
if ( ! lu - > login_orb )
2005-12-13 19:05:05 +03:00
goto alloc_fail ;
2005-04-17 02:20:36 +04:00
2007-02-04 22:57:38 +03:00
if ( sbp2util_create_command_orb_pool ( lu ) )
goto alloc_fail ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
/* Wait a second before trying to log in. Previously logged in
* initiators need a chance to reconnect . */
2006-08-14 20:56:00 +04:00
if ( msleep_interruptible ( 1000 ) ) {
2006-11-02 23:16:08 +03:00
sbp2_remove_device ( lu ) ;
2005-04-17 02:20:36 +04:00
return - EINTR ;
}
2005-11-07 14:31:39 +03:00
2006-11-02 23:16:08 +03:00
if ( sbp2_login_device ( lu ) ) {
sbp2_remove_device ( lu ) ;
2005-04-17 02:20:36 +04:00
return - EBUSY ;
}
2006-11-02 23:16:08 +03:00
sbp2_set_busy_timeout ( lu ) ;
sbp2_agent_reset ( lu , 1 ) ;
sbp2_max_speed_and_size ( lu ) ;
2005-04-17 02:20:36 +04:00
2008-02-04 01:07:44 +03:00
if ( lu - > workarounds & SBP2_WORKAROUND_DELAY_INQUIRY )
ssleep ( SBP2_INQUIRY_DELAY ) ;
2006-11-02 23:16:08 +03:00
error = scsi_add_device ( lu - > shost , 0 , lu - > ud - > id , 0 ) ;
2005-09-10 21:44:09 +04:00
if ( error ) {
2005-04-17 02:20:36 +04:00
SBP2_ERR ( " scsi_add_device failed " ) ;
2006-11-02 23:16:08 +03:00
sbp2_logout_device ( lu ) ;
sbp2_remove_device ( lu ) ;
2005-09-10 21:44:09 +04:00
return error ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
2005-12-13 19:05:05 +03:00
alloc_fail :
2006-11-02 23:16:08 +03:00
SBP2_ERR ( " Could not allocate memory for lu " ) ;
sbp2_remove_device ( lu ) ;
2005-12-13 19:05:05 +03:00
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
}
2006-11-02 23:16:08 +03:00
static void sbp2_remove_device ( struct sbp2_lu * lu )
2005-04-17 02:20:36 +04:00
{
2006-11-02 23:16:08 +03:00
struct sbp2_fwhost_info * hi ;
2007-08-11 13:52:08 +04:00
unsigned long flags ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
if ( ! lu )
2005-04-17 02:20:36 +04:00
return ;
2006-11-02 23:16:08 +03:00
hi = lu - > hi ;
2007-08-11 13:51:16 +04:00
if ( ! hi )
goto no_hi ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
if ( lu - > shost ) {
scsi_remove_host ( lu - > shost ) ;
scsi_host_put ( lu - > shost ) ;
2005-04-17 02:20:36 +04:00
}
2006-08-14 20:43:00 +04:00
flush_scheduled_work ( ) ;
2007-08-11 13:51:16 +04:00
sbp2util_remove_command_orb_pool ( lu , hi - > host ) ;
2005-04-17 02:20:36 +04:00
2007-08-11 13:52:08 +04:00
write_lock_irqsave ( & sbp2_hi_logical_units_lock , flags ) ;
2006-11-02 23:16:08 +03:00
list_del ( & lu - > lu_list ) ;
2007-08-11 13:52:08 +04:00
write_unlock_irqrestore ( & sbp2_hi_logical_units_lock , flags ) ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
if ( lu - > login_response )
2006-12-30 01:47:04 +03:00
dma_free_coherent ( hi - > host - > device . parent ,
2005-04-17 02:20:36 +04:00
sizeof ( struct sbp2_login_response ) ,
2006-11-02 23:16:08 +03:00
lu - > login_response ,
lu - > login_response_dma ) ;
if ( lu - > login_orb )
2006-12-30 01:47:04 +03:00
dma_free_coherent ( hi - > host - > device . parent ,
2005-04-17 02:20:36 +04:00
sizeof ( struct sbp2_login_orb ) ,
2006-11-02 23:16:08 +03:00
lu - > login_orb ,
lu - > login_orb_dma ) ;
if ( lu - > reconnect_orb )
2006-12-30 01:47:04 +03:00
dma_free_coherent ( hi - > host - > device . parent ,
2005-04-17 02:20:36 +04:00
sizeof ( struct sbp2_reconnect_orb ) ,
2006-11-02 23:16:08 +03:00
lu - > reconnect_orb ,
lu - > reconnect_orb_dma ) ;
if ( lu - > logout_orb )
2006-12-30 01:47:04 +03:00
dma_free_coherent ( hi - > host - > device . parent ,
2005-04-17 02:20:36 +04:00
sizeof ( struct sbp2_logout_orb ) ,
2006-11-02 23:16:08 +03:00
lu - > logout_orb ,
lu - > logout_orb_dma ) ;
if ( lu - > query_logins_orb )
2006-12-30 01:47:04 +03:00
dma_free_coherent ( hi - > host - > device . parent ,
2005-04-17 02:20:36 +04:00
sizeof ( struct sbp2_query_logins_orb ) ,
2006-11-02 23:16:08 +03:00
lu - > query_logins_orb ,
lu - > query_logins_orb_dma ) ;
if ( lu - > query_logins_response )
2006-12-30 01:47:04 +03:00
dma_free_coherent ( hi - > host - > device . parent ,
2005-04-17 02:20:36 +04:00
sizeof ( struct sbp2_query_logins_response ) ,
2006-11-02 23:16:08 +03:00
lu - > query_logins_response ,
lu - > query_logins_response_dma ) ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
if ( lu - > status_fifo_addr ! = CSR1212_INVALID_ADDR_SPACE )
2006-01-31 08:13:33 +03:00
hpsb_unregister_addrspace ( & sbp2_highlevel , hi - > host ,
2006-11-02 23:16:08 +03:00
lu - > status_fifo_addr ) ;
2006-01-31 08:13:33 +03:00
2009-05-01 01:43:31 +04:00
dev_set_drvdata ( & lu - > ud - > device , NULL ) ;
2005-04-17 02:20:36 +04:00
2007-08-11 13:51:16 +04:00
module_put ( hi - > host - > driver - > owner ) ;
no_hi :
2006-11-02 23:16:08 +03:00
kfree ( lu ) ;
2005-04-17 02:20:36 +04:00
}
# ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
/*
2006-11-02 23:16:08 +03:00
* Deal with write requests on adapters which do not support physical DMA or
* have it switched off .
2005-04-17 02:20:36 +04:00
*/
2005-11-07 14:31:39 +03: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-17 02:20:36 +04:00
{
2005-11-07 14:31:39 +03:00
memcpy ( bus_to_virt ( ( u32 ) addr ) , data , length ) ;
return RCODE_COMPLETE ;
2005-04-17 02:20:36 +04:00
}
/*
2006-11-02 23:16:08 +03:00
* Deal with read requests on adapters which do not support physical DMA or
* have it switched off .
2005-04-17 02:20:36 +04:00
*/
2005-11-07 14:31:39 +03: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-17 02:20:36 +04:00
{
2005-11-07 14:31:39 +03:00
memcpy ( data , bus_to_virt ( ( u32 ) addr ) , length ) ;
return RCODE_COMPLETE ;
2005-04-17 02:20:36 +04:00
}
# endif
/**************************************
* SBP - 2 protocol related section
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-11-02 23:16:08 +03:00
static int sbp2_query_logins ( struct sbp2_lu * lu )
2005-04-17 02:20:36 +04:00
{
2006-11-02 23:16:08 +03:00
struct sbp2_fwhost_info * hi = lu - > hi ;
2005-04-17 02:20:36 +04:00
quadlet_t data [ 2 ] ;
int max_logins ;
int active_logins ;
2006-11-02 23:16:08 +03:00
lu - > query_logins_orb - > reserved1 = 0x0 ;
lu - > query_logins_orb - > reserved2 = 0x0 ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03: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-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
lu - > query_logins_orb - > reserved_resp_length =
ORB_SET_QUERY_LOGINS_RESP_LENGTH (
sizeof ( struct sbp2_query_logins_response ) ) ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03: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-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
sbp2util_cpu_to_be32_buffer ( lu - > query_logins_orb ,
sizeof ( struct sbp2_query_logins_orb ) ) ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
memset ( lu - > query_logins_response , 0 ,
sizeof ( struct sbp2_query_logins_response ) ) ;
2005-04-17 02:20:36 +04:00
data [ 0 ] = ORB_SET_NODE_ID ( hi - > host - > node_id ) ;
2006-11-02 23:16:08 +03:00
data [ 1 ] = lu - > query_logins_orb_dma ;
2005-04-17 02:20:36 +04:00
sbp2util_cpu_to_be32_buffer ( data , 8 ) ;
2006-11-02 23:16:08 +03:00
hpsb_node_write ( lu - > ne , lu - > management_agent_addr , data , 8 ) ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
if ( sbp2util_access_timeout ( lu , 2 * HZ ) ) {
2005-04-17 02:20:36 +04:00
SBP2_INFO ( " Error querying logins to SBP-2 device - timed out " ) ;
2005-11-07 14:31:39 +03:00
return - EIO ;
2005-04-17 02:20:36 +04:00
}
2006-11-02 23:16:08 +03:00
if ( lu - > status_block . ORB_offset_lo ! = lu - > query_logins_orb_dma ) {
2005-04-17 02:20:36 +04:00
SBP2_INFO ( " Error querying logins to SBP-2 device - timed out " ) ;
2005-11-07 14:31:39 +03:00
return - EIO ;
2005-04-17 02:20:36 +04:00
}
2006-11-02 23:16:08 +03:00
if ( STATUS_TEST_RDS ( lu - > status_block . ORB_offset_hi_misc ) ) {
2006-07-24 00:18:00 +04:00
SBP2_INFO ( " Error querying logins to SBP-2 device - failed " ) ;
2005-11-07 14:31:39 +03:00
return - EIO ;
2005-04-17 02:20:36 +04:00
}
2006-11-02 23:16:08 +03:00
sbp2util_cpu_to_be32_buffer ( lu - > query_logins_response ,
sizeof ( struct sbp2_query_logins_response ) ) ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
max_logins = RESPONSE_GET_MAX_LOGINS (
lu - > query_logins_response - > length_max_logins ) ;
2006-06-13 02:13:11 +04:00
SBP2_INFO ( " Maximum concurrent logins supported: %d " , max_logins ) ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
active_logins = RESPONSE_GET_ACTIVE_LOGINS (
lu - > query_logins_response - > length_max_logins ) ;
2006-06-13 02:13:11 +04:00
SBP2_INFO ( " Number of active logins: %d " , active_logins ) ;
2005-04-17 02:20:36 +04:00
if ( active_logins > = max_logins ) {
2005-11-07 14:31:39 +03:00
return - EIO ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
}
2006-11-02 23:16:08 +03:00
static int sbp2_login_device ( struct sbp2_lu * lu )
2005-04-17 02:20:36 +04:00
{
2006-11-02 23:16:08 +03:00
struct sbp2_fwhost_info * hi = lu - > hi ;
2005-04-17 02:20:36 +04:00
quadlet_t data [ 2 ] ;
2006-11-02 23:16:08 +03:00
if ( ! lu - > login_orb )
2005-11-07 14:31:39 +03:00
return - EIO ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
if ( ! sbp2_exclusive_login & & sbp2_query_logins ( lu ) ) {
2006-11-02 23:16:08 +03:00
SBP2_INFO ( " Device does not support any more concurrent logins " ) ;
return - EIO ;
2005-04-17 02:20:36 +04:00
}
2006-11-02 23:16:08 +03:00
/* assume no password */
2006-11-02 23:16:08 +03:00
lu - > login_orb - > password_hi = 0 ;
lu - > login_orb - > password_lo = 0 ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03: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 23:16:08 +03:00
/* one second reconnect time */
2006-11-02 23:16:08 +03: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-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
lu - > login_orb - > passwd_resp_lengths =
2005-04-17 02:20:36 +04:00
ORB_SET_LOGIN_RESP_LENGTH ( sizeof ( struct sbp2_login_response ) ) ;
2006-11-02 23:16:08 +03: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-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
sbp2util_cpu_to_be32_buffer ( lu - > login_orb ,
sizeof ( struct sbp2_login_orb ) ) ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
memset ( lu - > login_response , 0 , sizeof ( struct sbp2_login_response ) ) ;
2005-04-17 02:20:36 +04:00
data [ 0 ] = ORB_SET_NODE_ID ( hi - > host - > node_id ) ;
2006-11-02 23:16:08 +03:00
data [ 1 ] = lu - > login_orb_dma ;
2005-04-17 02:20:36 +04:00
sbp2util_cpu_to_be32_buffer ( data , 8 ) ;
2006-11-02 23:16:08 +03:00
hpsb_node_write ( lu - > ne , lu - > management_agent_addr , data , 8 ) ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
/* wait up to 20 seconds for login status */
2006-11-02 23:16:08 +03:00
if ( sbp2util_access_timeout ( lu , 20 * HZ ) ) {
2006-07-24 00:19:00 +04:00
SBP2_ERR ( " Error logging into SBP-2 device - timed out " ) ;
2005-11-07 14:31:39 +03:00
return - EIO ;
2005-04-17 02:20:36 +04:00
}
2006-11-02 23:16:08 +03:00
/* make sure that the returned status matches the login ORB */
2006-11-02 23:16:08 +03:00
if ( lu - > status_block . ORB_offset_lo ! = lu - > login_orb_dma ) {
2006-07-24 00:18:00 +04:00
SBP2_ERR ( " Error logging into SBP-2 device - timed out " ) ;
2005-11-07 14:31:39 +03:00
return - EIO ;
2005-04-17 02:20:36 +04:00
}
2006-11-02 23:16:08 +03:00
if ( STATUS_TEST_RDS ( lu - > status_block . ORB_offset_hi_misc ) ) {
2006-07-24 00:18:00 +04:00
SBP2_ERR ( " Error logging into SBP-2 device - failed " ) ;
2005-11-07 14:31:39 +03:00
return - EIO ;
2005-04-17 02:20:36 +04:00
}
2006-11-02 23:16:08 +03: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-17 02:20:36 +04:00
SBP2_INFO ( " Logged into SBP-2 device " ) ;
2005-11-07 14:31:39 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2006-11-02 23:16:08 +03:00
static int sbp2_logout_device ( struct sbp2_lu * lu )
2005-04-17 02:20:36 +04:00
{
2006-11-02 23:16:08 +03:00
struct sbp2_fwhost_info * hi = lu - > hi ;
2005-04-17 02:20:36 +04:00
quadlet_t data [ 2 ] ;
int error ;
2006-11-02 23:16:08 +03:00
lu - > logout_orb - > reserved1 = 0x0 ;
lu - > logout_orb - > reserved2 = 0x0 ;
lu - > logout_orb - > reserved3 = 0x0 ;
lu - > logout_orb - > reserved4 = 0x0 ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03: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-17 02:20:36 +04:00
2006-11-02 23:16:08 +03: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-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
sbp2util_cpu_to_be32_buffer ( lu - > logout_orb ,
sizeof ( struct sbp2_logout_orb ) ) ;
2005-04-17 02:20:36 +04:00
data [ 0 ] = ORB_SET_NODE_ID ( hi - > host - > node_id ) ;
2006-11-02 23:16:08 +03:00
data [ 1 ] = lu - > logout_orb_dma ;
2005-04-17 02:20:36 +04:00
sbp2util_cpu_to_be32_buffer ( data , 8 ) ;
2006-11-02 23:16:08 +03:00
error = hpsb_node_write ( lu - > ne , lu - > management_agent_addr , data , 8 ) ;
2005-04-17 02:20:36 +04:00
if ( error )
return error ;
2006-11-02 23:16:08 +03:00
/* wait up to 1 second for the device to complete logout */
2006-11-02 23:16:08 +03:00
if ( sbp2util_access_timeout ( lu , HZ ) )
2005-04-17 02:20:36 +04:00
return - EIO ;
SBP2_INFO ( " Logged out of SBP-2 device " ) ;
2005-11-07 14:31:39 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2006-11-02 23:16:08 +03:00
static int sbp2_reconnect_device ( struct sbp2_lu * lu )
2005-04-17 02:20:36 +04:00
{
2006-11-02 23:16:08 +03:00
struct sbp2_fwhost_info * hi = lu - > hi ;
2005-04-17 02:20:36 +04:00
quadlet_t data [ 2 ] ;
int error ;
2006-11-02 23:16:08 +03:00
lu - > reconnect_orb - > reserved1 = 0x0 ;
lu - > reconnect_orb - > reserved2 = 0x0 ;
lu - > reconnect_orb - > reserved3 = 0x0 ;
lu - > reconnect_orb - > reserved4 = 0x0 ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03: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-17 02:20:36 +04:00
2006-11-02 23:16:08 +03: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-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
sbp2util_cpu_to_be32_buffer ( lu - > reconnect_orb ,
sizeof ( struct sbp2_reconnect_orb ) ) ;
2005-04-17 02:20:36 +04:00
data [ 0 ] = ORB_SET_NODE_ID ( hi - > host - > node_id ) ;
2006-11-02 23:16:08 +03:00
data [ 1 ] = lu - > reconnect_orb_dma ;
2005-04-17 02:20:36 +04:00
sbp2util_cpu_to_be32_buffer ( data , 8 ) ;
2006-11-02 23:16:08 +03:00
error = hpsb_node_write ( lu - > ne , lu - > management_agent_addr , data , 8 ) ;
2005-04-17 02:20:36 +04:00
if ( error )
return error ;
2006-11-02 23:16:08 +03:00
/* wait up to 1 second for reconnect status */
2006-11-02 23:16:08 +03:00
if ( sbp2util_access_timeout ( lu , HZ ) ) {
2006-07-24 00:19:00 +04:00
SBP2_ERR ( " Error reconnecting to SBP-2 device - timed out " ) ;
2005-11-07 14:31:39 +03:00
return - EIO ;
2005-04-17 02:20:36 +04:00
}
2006-11-02 23:16:08 +03:00
/* make sure that the returned status matches the reconnect ORB */
2006-11-02 23:16:08 +03:00
if ( lu - > status_block . ORB_offset_lo ! = lu - > reconnect_orb_dma ) {
2006-07-24 00:18:00 +04:00
SBP2_ERR ( " Error reconnecting to SBP-2 device - timed out " ) ;
2005-11-07 14:31:39 +03:00
return - EIO ;
2005-04-17 02:20:36 +04:00
}
2006-11-02 23:16:08 +03:00
if ( STATUS_TEST_RDS ( lu - > status_block . ORB_offset_hi_misc ) ) {
2006-07-24 00:18:00 +04:00
SBP2_ERR ( " Error reconnecting to SBP-2 device - failed " ) ;
2005-11-07 14:31:39 +03:00
return - EIO ;
2005-04-17 02:20:36 +04:00
}
2006-11-02 23:16:08 +03:00
SBP2_INFO ( " Reconnected to SBP-2 device " ) ;
2005-11-07 14:31:39 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
/*
2006-11-02 23:16:08 +03: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-17 02:20:36 +04:00
*/
2006-11-02 23:16:08 +03:00
static int sbp2_set_busy_timeout ( struct sbp2_lu * lu )
2005-04-17 02:20:36 +04:00
{
quadlet_t data ;
data = cpu_to_be32 ( SBP2_BUSY_TIMEOUT_VALUE ) ;
2006-11-02 23:16:08 +03:00
if ( hpsb_node_write ( lu - > ne , SBP2_BUSY_TIMEOUT_ADDRESS , & data , 4 ) )
2008-03-06 05:24:54 +03:00
SBP2_ERR ( " %s error " , __func__ ) ;
2005-11-07 14:31:39 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2006-11-02 23:16:08 +03:00
static void sbp2_parse_unit_directory ( struct sbp2_lu * lu ,
2005-04-17 02:20:36 +04:00
struct unit_directory * ud )
{
struct csr1212_keyval * kv ;
struct csr1212_dentry * dentry ;
u64 management_agent_addr ;
2009-01-24 21:41:46 +03:00
u32 unit_characteristics , firmware_revision , model ;
2006-05-16 00:04:59 +04:00
unsigned workarounds ;
2005-04-17 02:20:36 +04:00
int i ;
2006-11-02 23:16:08 +03:00
management_agent_addr = 0 ;
unit_characteristics = 0 ;
2009-01-24 21:41:46 +03:00
firmware_revision = SBP2_ROM_VALUE_MISSING ;
model = ud - > flags & UNIT_DIRECTORY_MODEL_ID ?
ud - > model_id : SBP2_ROM_VALUE_MISSING ;
2005-04-17 02:20:36 +04: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 23:16:08 +03:00
if ( kv - > key . type = = CSR1212_KV_TYPE_CSR_OFFSET )
2005-04-17 02:20:36 +04:00
management_agent_addr =
2005-11-07 14:31:39 +03:00
CSR1212_REGISTER_SPACE_BASE +
( kv - > value . csr_offset < < 2 ) ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
else if ( kv - > key . type = = CSR1212_KV_TYPE_IMMEDIATE )
2006-11-02 23:16:08 +03:00
lu - > lun = ORB_SET_LUN ( kv - > value . immediate ) ;
2005-04-17 02:20:36 +04:00
break ;
case SBP2_UNIT_CHARACTERISTICS_KEY :
2006-11-02 23:16:08 +03:00
/* FIXME: This is ignored so far.
* See SBP - 2 clause 7.4 .8 . */
2005-04-17 02:20:36 +04:00
unit_characteristics = kv - > value . immediate ;
break ;
case SBP2_FIRMWARE_REVISION_KEY :
firmware_revision = kv - > value . immediate ;
break ;
default :
2006-11-02 23:16:08 +03: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-17 02:20:36 +04:00
break ;
}
}
2006-05-16 00:04:59 +04:00
workarounds = sbp2_default_workarounds ;
2005-04-17 02:20:36 +04:00
2006-05-16 00:08:09 +04:00
if ( ! ( workarounds & SBP2_WORKAROUND_OVERRIDE ) )
for ( i = 0 ; i < ARRAY_SIZE ( sbp2_workarounds_table ) ; i + + ) {
2006-12-30 17:37:09 +03:00
if ( sbp2_workarounds_table [ i ] . firmware_revision ! =
SBP2_ROM_VALUE_WILDCARD & &
2006-05-16 00:08:09 +04:00
sbp2_workarounds_table [ i ] . firmware_revision ! =
( firmware_revision & 0xffff00 ) )
continue ;
2009-01-24 21:41:46 +03:00
if ( sbp2_workarounds_table [ i ] . model ! =
2006-12-30 17:37:09 +03:00
SBP2_ROM_VALUE_WILDCARD & &
2009-01-24 21:41:46 +03:00
sbp2_workarounds_table [ i ] . model ! = model )
2006-05-16 00:08:09 +04:00
continue ;
workarounds | = sbp2_workarounds_table [ i ] . workarounds ;
break ;
}
2005-04-17 02:20:36 +04:00
2006-05-16 00:04:59 +04:00
if ( workarounds )
2006-05-16 00:06:37 +04: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-16 00:04:59 +04:00
NODE_BUS_ARGS ( ud - > ne - > host , ud - > ne - > nodeid ) ,
2009-01-24 21:41:46 +03:00
workarounds , firmware_revision , ud - > vendor_id ,
2009-01-24 21:41:46 +03:00
model ) ;
2006-05-16 00:04:59 +04: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 23:16:08 +03:00
( sbp2_max_sectors * 512 ) > ( 128 * 1024 ) )
2006-11-02 23:16:08 +03:00
SBP2_INFO ( " Node " NODE_BUS_FMT " : Bridge only supports 128KB "
2006-05-16 00:04:59 +04: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 23:16:08 +03:00
sbp2_max_sectors ) ;
2006-05-16 00:04:59 +04:00
2005-04-17 02:20:36 +04: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 23:16:08 +03:00
struct unit_directory * parent_ud = container_of (
ud - > device . parent , struct unit_directory , device ) ;
sbp2_parse_unit_directory ( lu , parent_ud ) ;
2005-04-17 02:20:36 +04:00
} else {
2006-11-02 23:16:08 +03:00
lu - > management_agent_addr = management_agent_addr ;
lu - > workarounds = workarounds ;
2005-04-17 02:20:36 +04:00
if ( ud - > flags & UNIT_DIRECTORY_HAS_LUN )
2006-11-02 23:16:08 +03:00
lu - > lun = ORB_SET_LUN ( ud - > lun ) ;
2005-04-17 02:20:36 +04:00
}
}
2006-06-13 02:14:14 +04:00
# define SBP2_PAYLOAD_TO_BYTES(p) (1 << ((p) + 2))
2005-04-17 02:20:36 +04: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 23:16:08 +03:00
static int sbp2_max_speed_and_size ( struct sbp2_lu * lu )
2005-04-17 02:20:36 +04:00
{
2006-11-02 23:16:08 +03:00
struct sbp2_fwhost_info * hi = lu - > hi ;
2006-06-13 02:14:14 +04:00
u8 payload ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
lu - > speed_code = hi - > host - > speed [ NODEID_TO_NODE ( lu - > ne - > nodeid ) ] ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
if ( lu - > speed_code > sbp2_max_speed ) {
lu - > speed_code = sbp2_max_speed ;
2006-11-02 23:16:08 +03:00
SBP2_INFO ( " Reducing speed to %s " ,
hpsb_speedto_str [ sbp2_max_speed ] ) ;
2005-04-17 02:20:36 +04:00
}
/* Payload size is the lesser of what our speed supports and what
* our host supports . */
2006-11-02 23:16:08 +03:00
payload = min ( sbp2_speedto_max_payload [ lu - > speed_code ] ,
2006-06-13 02: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 23:16:08 +03:00
if ( lu - > ne - > host - > low_addr_space < ( 1ULL < < 32 ) )
2006-06-13 02:14:14 +04:00
while ( SBP2_PAYLOAD_TO_BYTES ( payload ) + 24 > PAGE_SIZE & &
payload )
payload - - ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
SBP2_INFO ( " Node " NODE_BUS_FMT " : Max speed [%s] - Max payload [%u] " ,
2006-11-02 23:16:08 +03:00
NODE_BUS_ARGS ( hi - > host , lu - > ne - > nodeid ) ,
hpsb_speedto_str [ lu - > speed_code ] ,
2006-11-02 23:16:08 +03:00
SBP2_PAYLOAD_TO_BYTES ( payload ) ) ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
lu - > max_payload_size = payload ;
2005-11-07 14:31:39 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2006-11-02 23:16:08 +03:00
static int sbp2_agent_reset ( struct sbp2_lu * lu , int wait )
2005-04-17 02:20:36 +04:00
{
quadlet_t data ;
u64 addr ;
int retval ;
2006-07-24 00:12:00 +04:00
unsigned long flags ;
2005-04-17 02:20:36 +04:00
2006-12-08 01:23:25 +03:00
/* flush lu->protocol_work */
2006-08-14 20:43:00 +04:00
if ( wait )
flush_scheduled_work ( ) ;
2005-04-17 02:20:36 +04:00
data = ntohl ( SBP2_AGENT_RESET_DATA ) ;
2006-11-02 23:16:08 +03:00
addr = lu - > command_block_agent_addr + SBP2_AGENT_RESET_OFFSET ;
2005-04-17 02:20:36 +04:00
if ( wait )
2006-11-02 23:16:08 +03:00
retval = hpsb_node_write ( lu - > ne , addr , & data , 4 ) ;
2005-04-17 02:20:36 +04:00
else
2006-11-02 23:16:08 +03:00
retval = sbp2util_node_write_no_wait ( lu - > ne , addr , & data , 4 ) ;
2005-04-17 02:20:36 +04:00
if ( retval < 0 ) {
SBP2_ERR ( " hpsb_node_write failed. \n " ) ;
return - EIO ;
}
2006-11-02 23:16:08 +03:00
/* make sure that the ORB_POINTER is written on next command */
2006-11-02 23:16:08 +03:00
spin_lock_irqsave ( & lu - > cmd_orb_lock , flags ) ;
lu - > last_orb = NULL ;
spin_unlock_irqrestore ( & lu - > cmd_orb_lock , flags ) ;
2005-04-17 02:20:36 +04:00
2005-11-07 14:31:39 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2008-08-09 22:16:24 +04:00
static int sbp2_prep_command_orb_sg ( struct sbp2_command_orb * orb ,
struct sbp2_fwhost_info * hi ,
struct sbp2_command_info * cmd ,
2008-08-14 11:28:14 +04:00
unsigned int sg_count ,
2008-08-09 22:16:24 +04:00
struct scatterlist * sg ,
u32 orb_direction ,
enum dma_data_direction dma_dir )
2005-12-13 19:05:03 +03:00
{
2008-08-09 22:16:24 +04:00
struct device * dmadev = hi - > host - > device . parent ;
2008-08-14 11:28:14 +04:00
struct sbp2_unrestricted_page_table * pt ;
int i , n ;
n = dma_map_sg ( dmadev , sg , sg_count , dma_dir ) ;
if ( n = = 0 )
return - ENOMEM ;
2008-08-09 22:16:24 +04:00
2005-12-13 19:05:03 +03:00
orb - > data_descriptor_hi = ORB_SET_NODE_ID ( hi - > host - > node_id ) ;
orb - > misc | = ORB_SET_DIRECTION ( orb_direction ) ;
2006-11-02 23:16:08 +03:00
/* special case if only one element (and less than 64KB in size) */
2008-08-14 11:28:14 +04:00
if ( n = = 1 ) {
orb - > misc | = ORB_SET_DATA_SIZE ( sg_dma_len ( sg ) ) ;
orb - > data_descriptor_lo = sg_dma_address ( sg ) ;
2005-12-13 19:05:03 +03:00
} else {
2008-08-14 11:28:14 +04:00
pt = & cmd - > scatter_gather_element [ 0 ] ;
2005-12-13 19:05:03 +03:00
2008-08-09 22:16:24 +04:00
dma_sync_single_for_cpu ( dmadev , cmd - > sge_dma ,
2008-08-09 22:13:00 +04:00
sizeof ( cmd - > scatter_gather_element ) ,
DMA_TO_DEVICE ) ;
2008-08-14 11:28:14 +04:00
for_each_sg ( sg , sg , n , i ) {
pt [ i ] . high = cpu_to_be32 ( sg_dma_len ( sg ) < < 16 ) ;
pt [ i ] . low = cpu_to_be32 ( sg_dma_address ( sg ) ) ;
2005-12-13 19:05:03 +03:00
}
2008-08-14 11:28:14 +04:00
orb - > misc | = ORB_SET_PAGE_TABLE_PRESENT ( 0x1 ) |
ORB_SET_DATA_SIZE ( n ) ;
orb - > data_descriptor_lo = cmd - > sge_dma ;
2008-08-09 22:13:00 +04:00
2008-08-09 22:16:24 +04:00
dma_sync_single_for_device ( dmadev , cmd - > sge_dma ,
2008-08-09 22:13:00 +04:00
sizeof ( cmd - > scatter_gather_element ) ,
DMA_TO_DEVICE ) ;
2005-12-13 19:05:03 +03:00
}
2008-08-09 22:16:24 +04:00
return 0 ;
2005-12-13 19:05:03 +03:00
}
2008-08-09 22:16:24 +04:00
static int sbp2_create_command_orb ( struct sbp2_lu * lu ,
struct sbp2_command_info * cmd ,
struct scsi_cmnd * SCpnt )
2005-04-17 02:20:36 +04:00
{
2008-08-09 22:13:00 +04:00
struct device * dmadev = lu - > hi - > host - > device . parent ;
2006-11-02 23:16:08 +03:00
struct sbp2_command_orb * orb = & cmd - > command_orb ;
2008-05-04 18:54:14 +04:00
unsigned int scsi_request_bufflen = scsi_bufflen ( SCpnt ) ;
enum dma_data_direction dma_dir = SCpnt - > sc_data_direction ;
2008-08-09 22:16:24 +04:00
u32 orb_direction ;
int ret ;
2005-04-17 02:20:36 +04:00
2008-08-09 22:13:00 +04:00
dma_sync_single_for_cpu ( dmadev , cmd - > command_orb_dma ,
sizeof ( struct sbp2_command_orb ) , DMA_TO_DEVICE ) ;
2005-04-17 02:20:36 +04:00
/*
2006-11-02 23:16:08 +03:00
* Set - up our command ORB .
2005-04-17 02:20:36 +04: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 23:16:08 +03: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-17 02:20:36 +04:00
2005-12-13 07:03:24 +03:00
if ( dma_dir = = DMA_NONE )
2005-11-07 14:31:39 +03:00
orb_direction = ORB_DIRECTION_NO_DATA_TRANSFER ;
2005-12-13 07:03:24 +03:00
else if ( dma_dir = = DMA_TO_DEVICE & & scsi_request_bufflen )
2005-11-07 14:31:39 +03:00
orb_direction = ORB_DIRECTION_WRITE_TO_MEDIA ;
2005-12-13 07:03:24 +03:00
else if ( dma_dir = = DMA_FROM_DEVICE & & scsi_request_bufflen )
2005-11-07 14:31:39 +03:00
orb_direction = ORB_DIRECTION_READ_FROM_MEDIA ;
2005-12-13 07:03:24 +03:00
else {
2006-11-02 23:16:08 +03:00
SBP2_INFO ( " Falling back to DMA_NONE " ) ;
2005-12-13 07:03:24 +03:00
orb_direction = ORB_DIRECTION_NO_DATA_TRANSFER ;
2005-04-17 02:20:36 +04:00
}
2006-11-02 23:16:08 +03:00
/* set up our page table stuff */
2005-04-17 02:20:36 +04:00
if ( orb_direction = = ORB_DIRECTION_NO_DATA_TRANSFER ) {
2006-11-02 23:16:08 +03:00
orb - > data_descriptor_hi = 0x0 ;
orb - > data_descriptor_lo = 0x0 ;
orb - > misc | = ORB_SET_DIRECTION ( 1 ) ;
2008-08-09 22:16:24 +04:00
ret = 0 ;
} else {
ret = sbp2_prep_command_orb_sg ( orb , lu - > hi , cmd ,
scsi_sg_count ( SCpnt ) ,
scsi_sglist ( SCpnt ) ,
orb_direction , dma_dir ) ;
}
2006-11-02 23:16:08 +03:00
sbp2util_cpu_to_be32_buffer ( orb , sizeof ( * orb ) ) ;
2005-04-17 02:20:36 +04:00
2008-05-04 18:54:14 +04:00
memset ( orb - > cdb , 0 , sizeof ( orb - > cdb ) ) ;
memcpy ( orb - > cdb , SCpnt - > cmnd , SCpnt - > cmd_len ) ;
2008-08-09 22:13:00 +04:00
dma_sync_single_for_device ( dmadev , cmd - > command_orb_dma ,
sizeof ( struct sbp2_command_orb ) , DMA_TO_DEVICE ) ;
2008-08-09 22:16:24 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
2006-11-02 23:16:08 +03:00
static void sbp2_link_orb_command ( struct sbp2_lu * lu ,
struct sbp2_command_info * cmd )
2005-04-17 02:20:36 +04:00
{
2006-11-02 23:16:08 +03:00
struct sbp2_fwhost_info * hi = lu - > hi ;
2006-07-24 00:12:00 +04:00
struct sbp2_command_orb * last_orb ;
dma_addr_t last_orb_dma ;
2006-11-02 23:16:08 +03:00
u64 addr = lu - > command_block_agent_addr ;
2006-07-24 00:12:00 +04:00
quadlet_t data [ 2 ] ;
size_t length ;
unsigned long flags ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
/* check to see if there are any previous orbs to use */
2006-11-02 23:16:08 +03:00
spin_lock_irqsave ( & lu - > cmd_orb_lock , flags ) ;
last_orb = lu - > last_orb ;
last_orb_dma = lu - > last_orb_dma ;
2006-07-24 00:12:00 +04:00
if ( ! last_orb ) {
2005-04-17 02:20:36 +04:00
/*
2006-07-24 00:12:00 +04:00
* last_orb = = NULL means : We know that the target ' s fetch agent
* is not active right now .
2005-04-17 02:20:36 +04:00
*/
2006-07-24 00:12:00 +04:00
addr + = SBP2_ORB_POINTER_OFFSET ;
2005-04-17 02:20:36 +04:00
data [ 0 ] = ORB_SET_NODE_ID ( hi - > host - > node_id ) ;
2006-11-02 23:16:08 +03:00
data [ 1 ] = cmd - > command_orb_dma ;
2005-04-17 02:20:36 +04:00
sbp2util_cpu_to_be32_buffer ( data , 8 ) ;
2006-07-24 00:12:00 +04:00
length = 8 ;
2005-04-17 02:20:36 +04:00
} else {
/*
2006-07-24 00:12:00 +04: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-17 02:20:36 +04:00
*/
2006-12-30 01:47:04 +03:00
dma_sync_single_for_cpu ( hi - > host - > device . parent , last_orb_dma ,
2006-11-22 23:44:34 +03:00
sizeof ( struct sbp2_command_orb ) ,
DMA_TO_DEVICE ) ;
2006-11-02 23:16:08 +03:00
last_orb - > next_ORB_lo = cpu_to_be32 ( cmd - > command_orb_dma ) ;
2006-07-24 00:12:00 +04:00
wmb ( ) ;
2005-04-17 02:20:36 +04:00
/* Tells hardware that this pointer is valid */
2006-07-24 00:12:00 +04:00
last_orb - > next_ORB_hi = 0 ;
2006-12-30 01:47:04 +03:00
dma_sync_single_for_device ( hi - > host - > device . parent ,
last_orb_dma ,
2006-11-22 23:44:34 +03:00
sizeof ( struct sbp2_command_orb ) ,
DMA_TO_DEVICE ) ;
2006-07-24 00:12:00 +04:00
addr + = SBP2_DOORBELL_OFFSET ;
data [ 0 ] = 0 ;
length = 4 ;
}
2006-11-02 23:16:08 +03: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-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
if ( sbp2util_node_write_no_wait ( lu - > ne , addr , data , length ) ) {
2006-08-14 20:43:00 +04: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 23:16:08 +03:00
scsi_block_requests ( lu - > shost ) ;
PREPARE_WORK ( & lu - > protocol_work ,
2006-08-14 20:43:00 +04:00
last_orb ? sbp2util_write_doorbell :
2006-12-08 01:23:25 +03:00
sbp2util_write_orb_pointer ) ;
2006-11-02 23:16:08 +03:00
schedule_work ( & lu - > protocol_work ) ;
2006-08-14 20:43:00 +04:00
}
2005-04-17 02:20:36 +04:00
}
2006-11-02 23:16:08 +03:00
static int sbp2_send_command ( struct sbp2_lu * lu , struct scsi_cmnd * SCpnt ,
2005-04-17 02:20:36 +04:00
void ( * done ) ( struct scsi_cmnd * ) )
{
2006-11-02 23:16:08 +03:00
struct sbp2_command_info * cmd ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
cmd = sbp2util_allocate_command_orb ( lu , SCpnt , done ) ;
if ( ! cmd )
2005-11-07 14:31:39 +03:00
return - EIO ;
2005-04-17 02:20:36 +04:00
2008-08-09 22:16:24 +04:00
if ( sbp2_create_command_orb ( lu , cmd , SCpnt ) )
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
2008-08-09 22:16:24 +04:00
sbp2_link_orb_command ( lu , cmd ) ;
2005-11-07 14:31:39 +03:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
/*
* Translates SBP - 2 status into SCSI sense data for check conditions
*/
2006-11-02 23:16:08 +03:00
static unsigned int sbp2_status_to_sense_data ( unchar * sbp2_status ,
unchar * sense_data )
2005-04-17 02:20:36 +04:00
{
2006-11-02 23:16:08 +03:00
/* OK, it's pretty ugly... ;-) */
2005-04-17 02:20:36 +04: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 23:16:08 +03:00
return sbp2_status [ 8 ] & 0x3f ;
2005-04-17 02:20:36 +04:00
}
2006-07-24 00:16:00 +04: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-17 02:20:36 +04:00
{
2006-11-02 23:16:08 +03:00
struct sbp2_fwhost_info * hi ;
2006-11-02 23:16:08 +03:00
struct sbp2_lu * lu = NULL , * lu_tmp ;
2005-04-17 02:20:36 +04:00
struct scsi_cmnd * SCpnt = NULL ;
2006-07-24 00:16:00 +04:00
struct sbp2_status_block * sb ;
2005-04-17 02:20:36 +04:00
u32 scsi_status = SBP2_SCSI_STATUS_GOOD ;
2006-11-02 23:16:08 +03:00
struct sbp2_command_info * cmd ;
2005-11-07 14:29:39 +03:00
unsigned long flags ;
2005-04-17 02:20:36 +04:00
2006-07-24 00:18:00 +04: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-17 02:20:36 +04:00
SBP2_ERR ( " host is NULL - this is bad! " ) ;
2005-11-07 14:31:39 +03:00
return RCODE_ADDRESS_ERROR ;
2005-04-17 02:20:36 +04:00
}
hi = hpsb_get_hostinfo ( & sbp2_highlevel , host ) ;
2006-07-24 00:18:00 +04:00
if ( unlikely ( ! hi ) ) {
2005-04-17 02:20:36 +04:00
SBP2_ERR ( " host info is NULL - this is bad! " ) ;
2005-11-07 14:31:39 +03:00
return RCODE_ADDRESS_ERROR ;
2005-04-17 02:20:36 +04:00
}
2006-11-02 23:16:08 +03:00
/* Find the unit which wrote the status. */
2007-08-11 13:52:08 +04:00
read_lock_irqsave ( & sbp2_hi_logical_units_lock , flags ) ;
2006-11-02 23:16:08 +03: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-17 02:20:36 +04:00
break ;
}
}
2007-08-11 13:52:08 +04:00
read_unlock_irqrestore ( & sbp2_hi_logical_units_lock , flags ) ;
2006-11-02 23:16:08 +03:00
if ( unlikely ( ! lu ) ) {
SBP2_ERR ( " lu is NULL - device is gone? " ) ;
2005-11-07 14:31:39 +03:00
return RCODE_ADDRESS_ERROR ;
2005-04-17 02:20:36 +04:00
}
2006-11-02 23:16:08 +03:00
/* Put response into lu status fifo buffer. The first two bytes
2006-07-24 00:16:00 +04: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 23:16:08 +03:00
* is implied to be zeros . */
2006-11-02 23:16:08 +03:00
sb = & lu - > status_block ;
2006-07-24 00:16:00 +04: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-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
/* Ignore unsolicited status. Handle command ORB status. */
2006-07-24 00:18:00 +04:00
if ( unlikely ( STATUS_GET_SRC ( sb - > ORB_offset_hi_misc ) = = 2 ) )
2006-11-02 23:16:08 +03:00
cmd = NULL ;
2006-07-24 00:18:00 +04:00
else
2006-11-02 23:16:08 +03:00
cmd = sbp2util_find_command_for_orb ( lu , sb - > ORB_offset_lo ) ;
if ( cmd ) {
2006-11-02 23:16:08 +03:00
/* Grab SCSI command pointers and check status. */
2006-07-24 00:18:00 +04: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 23:16:08 +03: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-17 02:20:36 +04:00
if ( SCpnt ) {
2006-08-14 20:51:00 +04:00
u32 h = sb - > ORB_offset_hi_misc ;
u32 r = STATUS_GET_RESP ( h ) ;
if ( r ! = RESP_STATUS_REQUEST_COMPLETE ) {
2006-11-02 23:16:08 +03:00
SBP2_INFO ( " resp 0x%x, sbp_status 0x%x " ,
2006-08-14 20:51:00 +04:00
r , STATUS_GET_SBP_STATUS ( h ) ) ;
2006-07-24 00:18:00 +04:00
scsi_status =
2006-08-14 20:51:00 +04:00
r = = RESP_STATUS_TRANSPORT_FAILURE ?
SBP2_SCSI_STATUS_BUSY :
2006-07-24 00:18:00 +04:00
SBP2_SCSI_STATUS_COMMAND_TERMINATED ;
2006-08-14 20:51:00 +04:00
}
2006-11-02 23:16:08 +03:00
2006-11-02 23:16:08 +03:00
if ( STATUS_GET_LEN ( h ) > 1 )
2006-07-24 00:16:00 +04:00
scsi_status = sbp2_status_to_sense_data (
( unchar * ) sb , SCpnt - > sense_buffer ) ;
2006-11-02 23:16:08 +03:00
2006-11-02 23:16:08 +03:00
if ( STATUS_TEST_DEAD ( h ) )
2006-11-02 23:16:08 +03:00
sbp2_agent_reset ( lu , 0 ) ;
2005-04-17 02:20:36 +04:00
}
2006-11-02 23:16:08 +03:00
/* Check here to see if there are no commands in-use. If there
2006-07-24 00:12:00 +04: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 23:16:08 +03:00
* to refetch the next_ORB . */
2006-11-02 23:16:08 +03: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-17 02:20:36 +04:00
} else {
2006-11-02 23:16:08 +03:00
/* It's probably status after a management request. */
2006-11-02 23:16:08 +03: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 23:16:08 +03:00
wake_up_interruptible ( & sbp2_access_wq ) ;
2006-07-24 00:19:00 +04:00
}
2005-04-17 02:20:36 +04:00
}
2006-11-02 23:16:08 +03:00
if ( SCpnt )
2006-11-02 23:16:08 +03:00
sbp2scsi_complete_command ( lu , scsi_status , SCpnt ,
cmd - > Current_done ) ;
2005-11-07 14:31:39 +03:00
return RCODE_COMPLETE ;
2005-04-17 02:20:36 +04:00
}
/**************************************
* SCSI interface related section
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int sbp2scsi_queuecommand ( struct scsi_cmnd * SCpnt ,
void ( * done ) ( struct scsi_cmnd * ) )
{
2006-11-02 23:16:08 +03:00
struct sbp2_lu * lu = ( struct sbp2_lu * ) SCpnt - > device - > host - > hostdata [ 0 ] ;
2006-11-02 23:16:08 +03:00
struct sbp2_fwhost_info * hi ;
2005-09-30 22:59:06 +04:00
int result = DID_NO_CONNECT < < 16 ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
if ( unlikely ( ! sbp2util_node_is_available ( lu ) ) )
2005-09-30 22:59:06 +04:00
goto done ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
hi = lu - > hi ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
if ( unlikely ( ! hi ) ) {
2006-11-02 23:16:08 +03:00
SBP2_ERR ( " sbp2_fwhost_info is NULL - this is bad! " ) ;
2005-09-30 22:59:06 +04:00
goto done ;
2005-04-17 02:20:36 +04:00
}
2006-11-02 23:16:08 +03: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 23:16:08 +03:00
if ( unlikely ( SCpnt - > device - > lun ) )
2005-09-30 22:59:06 +04:00
goto done ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
if ( unlikely ( ! hpsb_node_entry_valid ( lu - > ne ) ) ) {
2005-04-17 02:20:36 +04:00
SBP2_ERR ( " Bus reset in progress - rejecting command " ) ;
2005-09-30 22:59:06 +04:00
result = DID_BUS_BUSY < < 16 ;
goto done ;
2005-04-17 02:20:36 +04:00
}
2006-11-02 23:16:08 +03:00
/* Bidirectional commands are not yet implemented,
* and unknown transfer direction not handled . */
2006-11-02 23:16:08 +03:00
if ( unlikely ( SCpnt - > sc_data_direction = = DMA_BIDIRECTIONAL ) ) {
2005-12-13 07:03:24 +03:00
SBP2_ERR ( " Cannot handle DMA_BIDIRECTIONAL - rejecting command " ) ;
result = DID_ERROR < < 16 ;
goto done ;
}
2006-11-02 23:16:08 +03:00
if ( sbp2_send_command ( lu , SCpnt , done ) ) {
2005-04-17 02:20:36 +04:00
SBP2_ERR ( " Error sending SCSI command " ) ;
2006-11-02 23:16:08 +03:00
sbp2scsi_complete_command ( lu ,
SBP2_SCSI_STATUS_SELECTION_TIMEOUT ,
2005-04-17 02:20:36 +04:00
SCpnt , done ) ;
}
2005-09-30 22:59:06 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
2005-09-30 22:59:06 +04:00
done :
SCpnt - > result = result ;
done ( SCpnt ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2006-11-02 23:16:08 +03:00
static void sbp2scsi_complete_all_commands ( struct sbp2_lu * lu , u32 status )
2005-04-17 02:20:36 +04:00
{
struct list_head * lh ;
2006-11-02 23:16:08 +03:00
struct sbp2_command_info * cmd ;
2005-11-07 14:29:39 +03:00
unsigned long flags ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03: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 ) ;
sbp2util_mark_command_completed ( lu , cmd ) ;
if ( cmd - > Current_SCpnt ) {
cmd - > Current_SCpnt - > result = status < < 16 ;
cmd - > Current_done ( cmd - > Current_SCpnt ) ;
2005-04-17 02:20:36 +04:00
}
}
2006-11-02 23:16:08 +03:00
spin_unlock_irqrestore ( & lu - > cmd_orb_lock , flags ) ;
2005-04-17 02:20:36 +04:00
return ;
}
/*
2006-11-02 23:16:08 +03:00
* Complete a regular SCSI command . Can be called in atomic context .
2005-04-17 02:20:36 +04:00
*/
2006-11-02 23:16:08 +03:00
static void sbp2scsi_complete_command ( struct sbp2_lu * lu , u32 scsi_status ,
struct scsi_cmnd * SCpnt ,
2005-04-17 02:20:36 +04:00
void ( * done ) ( struct scsi_cmnd * ) )
{
if ( ! SCpnt ) {
SBP2_ERR ( " SCpnt is NULL " ) ;
return ;
}
switch ( scsi_status ) {
2005-11-07 14:31:39 +03:00
case SBP2_SCSI_STATUS_GOOD :
2006-03-29 05:03:45 +04:00
SCpnt - > result = DID_OK < < 16 ;
2005-11-07 14:31:39 +03:00
break ;
2005-04-17 02:20:36 +04:00
2005-11-07 14:31:39 +03:00
case SBP2_SCSI_STATUS_BUSY :
SBP2_ERR ( " SBP2_SCSI_STATUS_BUSY " ) ;
SCpnt - > result = DID_BUS_BUSY < < 16 ;
break ;
2005-04-17 02:20:36 +04:00
2005-11-07 14:31:39 +03:00
case SBP2_SCSI_STATUS_CHECK_CONDITION :
2006-03-29 05:03:45 +04:00
SCpnt - > result = CHECK_CONDITION < < 1 | DID_OK < < 16 ;
2005-11-07 14:31:39 +03:00
break ;
2005-04-17 02:20:36 +04:00
2005-11-07 14:31:39 +03: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-17 02:20:36 +04:00
2005-11-07 14:31:39 +03: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-17 02:20:36 +04:00
2005-11-07 14:31:39 +03:00
default :
SBP2_ERR ( " Unsupported SCSI status = %x " , scsi_status ) ;
SCpnt - > result = DID_ERROR < < 16 ;
2005-04-17 02:20:36 +04:00
}
2006-11-02 23:16:08 +03: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 23:16:08 +03:00
if ( ! hpsb_node_entry_valid ( lu - > ne )
2005-11-07 14:31:39 +03:00
& & ( scsi_status ! = SBP2_SCSI_STATUS_GOOD ) ) {
2005-04-17 02:20:36 +04:00
SBP2_ERR ( " Completing command with busy (bus reset) " ) ;
SCpnt - > result = DID_BUS_BUSY < < 16 ;
}
2006-11-02 23:16:08 +03:00
/* Tell the SCSI stack that we're done with this command. */
2005-11-07 14:31:39 +03:00
done ( SCpnt ) ;
2005-04-17 02:20:36 +04:00
}
2005-09-30 22:59:06 +04:00
static int sbp2scsi_slave_alloc ( struct scsi_device * sdev )
2005-04-17 02:20:36 +04:00
{
2006-11-02 23:16:08 +03:00
struct sbp2_lu * lu = ( struct sbp2_lu * ) sdev - > host - > hostdata [ 0 ] ;
2006-02-15 06:04:19 +03:00
2008-02-17 16:57:10 +03:00
if ( sdev - > lun ! = 0 | | sdev - > id ! = lu - > ud - > id | | sdev - > channel ! = 0 )
return - ENODEV ;
2006-11-02 23:16:08 +03:00
lu - > sdev = sdev ;
2006-08-07 22:48:00 +04:00
sdev - > allow_restart = 1 ;
2006-02-15 06:04:19 +03:00
2008-01-28 00:32:22 +03:00
/* SBP-2 requires quadlet alignment of the data buffers. */
blk_queue_update_dma_alignment ( sdev - > request_queue , 4 - 1 ) ;
2008-01-01 19:00:10 +03:00
2006-11-02 23:16:08 +03:00
if ( lu - > workarounds & SBP2_WORKAROUND_INQUIRY_36 )
2006-02-15 06:04:19 +03:00
sdev - > inquiry_len = 36 ;
2005-09-30 22:59:06 +04:00
return 0 ;
}
static int sbp2scsi_slave_configure ( struct scsi_device * sdev )
{
2006-11-02 23:16:08 +03:00
struct sbp2_lu * lu = ( struct sbp2_lu * ) sdev - > host - > hostdata [ 0 ] ;
2006-05-16 00:04:59 +04:00
2005-11-07 14:31:24 +03:00
sdev - > use_10_for_rw = 1 ;
2006-05-16 00:04:59 +04:00
2008-05-11 02:37:14 +04:00
if ( sbp2_exclusive_login )
sdev - > manage_start_stop = 1 ;
2007-01-10 22:17:15 +03:00
if ( sdev - > type = = TYPE_ROM )
sdev - > use_10_for_ms = 1 ;
2006-05-16 00:04:59 +04:00
if ( sdev - > type = = TYPE_DISK & &
2006-11-02 23:16:08 +03:00
lu - > workarounds & SBP2_WORKAROUND_MODE_SENSE_8 )
2006-05-16 00:04:59 +04:00
sdev - > skip_ms_page_8 = 1 ;
2006-11-02 23:16:08 +03:00
if ( lu - > workarounds & SBP2_WORKAROUND_FIX_CAPACITY )
2006-05-16 00:06:37 +04:00
sdev - > fix_capacity = 1 ;
2008-05-11 02:35:55 +04:00
if ( lu - > workarounds & SBP2_WORKAROUND_POWER_CONDITION )
sdev - > start_stop_pwr_cond = 1 ;
2007-12-16 19:31:26 +03:00
if ( lu - > workarounds & SBP2_WORKAROUND_128K_MAX_TRANS )
2010-02-26 08:20:38 +03:00
blk_queue_max_hw_sectors ( sdev - > request_queue , 128 * 1024 / 512 ) ;
2008-08-14 11:28:14 +04:00
blk_queue_max_segment_size ( sdev - > request_queue , SBP2_MAX_SEG_SIZE ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2005-09-30 22:59:06 +04:00
static void sbp2scsi_slave_destroy ( struct scsi_device * sdev )
{
2006-11-02 23:16:08 +03:00
( ( struct sbp2_lu * ) sdev - > host - > hostdata [ 0 ] ) - > sdev = NULL ;
2005-09-30 22:59:06 +04:00
return ;
}
2005-04-17 02:20:36 +04:00
/*
2006-11-02 23:16:08 +03:00
* Called by scsi stack when something has really gone wrong .
* Usually called when a command has timed - out for some reason .
2005-04-17 02:20:36 +04:00
*/
static int sbp2scsi_abort ( struct scsi_cmnd * SCpnt )
{
2006-11-02 23:16:08 +03:00
struct sbp2_lu * lu = ( struct sbp2_lu * ) SCpnt - > device - > host - > hostdata [ 0 ] ;
struct sbp2_command_info * cmd ;
2006-04-01 23:11:41 +04:00
unsigned long flags ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
SBP2_INFO ( " aborting sbp2 command " ) ;
2005-04-17 02:20:36 +04:00
scsi_print_command ( SCpnt ) ;
2006-11-02 23:16:08 +03:00
if ( sbp2util_node_is_available ( lu ) ) {
sbp2_agent_reset ( lu , 1 ) ;
2005-04-17 02:20:36 +04:00
2006-09-11 22:17:14 +04:00
/* Return a matching command structure to the free pool. */
2006-11-02 23:16:08 +03:00
spin_lock_irqsave ( & lu - > cmd_orb_lock , flags ) ;
cmd = sbp2util_find_command_for_SCpnt ( lu , SCpnt ) ;
if ( cmd ) {
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-17 02:20:36 +04:00
}
}
2006-11-02 23:16:08 +03:00
spin_unlock_irqrestore ( & lu - > cmd_orb_lock , flags ) ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
sbp2scsi_complete_all_commands ( lu , DID_BUS_BUSY ) ;
2005-04-17 02:20:36 +04:00
}
2005-11-07 14:31:39 +03:00
return SUCCESS ;
2005-04-17 02:20:36 +04:00
}
/*
* Called by scsi stack when something has really gone wrong .
*/
2005-09-30 22:59:06 +04:00
static int sbp2scsi_reset ( struct scsi_cmnd * SCpnt )
2005-04-17 02:20:36 +04:00
{
2006-11-02 23:16:08 +03:00
struct sbp2_lu * lu = ( struct sbp2_lu * ) SCpnt - > device - > host - > hostdata [ 0 ] ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
SBP2_INFO ( " reset requested " ) ;
2005-04-17 02:20:36 +04:00
2006-11-02 23:16:08 +03:00
if ( sbp2util_node_is_available ( lu ) ) {
2006-11-02 23:16:08 +03:00
SBP2_INFO ( " generating sbp2 fetch agent reset " ) ;
2006-11-02 23:16:08 +03:00
sbp2_agent_reset ( lu , 1 ) ;
2005-04-17 02:20:36 +04:00
}
2005-09-30 22:59:06 +04:00
return SUCCESS ;
2005-05-28 15:55:48 +04:00
}
2005-11-07 14:31:39 +03:00
static ssize_t sbp2_sysfs_ieee1394_id_show ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
2005-04-17 02:20:36 +04:00
{
struct scsi_device * sdev ;
2006-11-02 23:16:08 +03:00
struct sbp2_lu * lu ;
2005-04-17 02:20:36 +04:00
if ( ! ( sdev = to_scsi_device ( dev ) ) )
return 0 ;
2006-11-02 23:16:08 +03:00
if ( ! ( lu = ( struct sbp2_lu * ) sdev - > host - > hostdata [ 0 ] ) )
2005-04-17 02:20:36 +04:00
return 0 ;
2007-05-27 15:17:15 +04: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-17 02:20:36 +04: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 23:16:08 +03:00
if ( sbp2_serialize_io ) {
sbp2_shost_template . can_queue = 1 ;
sbp2_shost_template . cmd_per_lun = 1 ;
2005-04-17 02:20:36 +04:00
}
2006-11-02 23:16:08 +03:00
sbp2_shost_template . max_sectors = sbp2_max_sectors ;
2005-04-17 02:20:36 +04: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 ) ;