aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tc/Makefile
Commit message (Expand)AuthorAge
* Linux-2.6.12-rc2v2.6.12-rc2Linus Torvalds2005-04-16
n value='wip-ft-irq-flag'>wip-ft-irq-flag The LITMUS^RT kernel.Bjoern Brandenburg
aboutsummaryrefslogblamecommitdiffstats
path: root/drivers/ieee1394/sbp2.c
blob: a373c18cf7b8fe8bd077c47b0808abea743e573f (plain) (tree)






























                                                                            

                                                                         
  

                                                                          
  












                                                                             
                                        

   
                         





                              

                         
                     

                              
                        





                            
                       
                            
                              
 
                          

                      





                                         







                             

                      
                     
                          
                             
                                  

                           

                 











                                                                          

                                                         

                                                                         

  

                                                                                
   
                                 


                                                                             

  









                                                                            
   
                            

                                                                     
                                                             






                                                                          





                                                                          
   
                                    
                                                                      
                                                                   
                                                                   

  


                                                                           
  









                                                                               




                                                                               
  


                                                                           




                                                                          



                                                                          
   





                                                                             
                                                                           
                                                                            

                                                                              
                                                                                

                               




















                                                                                
 

                                                               
 


          

                                                                                
                                                                    





                                                                  


                                                                              

                                                       
                                                               

                                                     
 


                                                                              

                                                 
                                               

                                           


                                           
                                                  


                                    




                                                                               
                                                   

                                                    


      
















                                                                               
                                                  
                                           


                                        




                                              




















                                                                              
                                                        













                                                            


                                                         

                                                     
 
  




                                                                            
   

                              
                     

                              
                                                       
                                                   
                                                   
                                                                      

                                                                          
          


                                                         

                                                                          
          

                                                                        
                                                                  

                                                                     




                                                                          

                                                   
                                                                  
                                                                         
          




                                                                         






                                                                       




                                                                       






                                                                       
         

  



                                        



                                                                        
                                                                        




                                                         




                                                                        
                                                                        




                                                         


                               

                                                        

      
                                               
 
  

                                                           
   
                                                                   
 
                      
 
                                                    

                                                                      
                             

 
                                          




                                 


                                                                      

                                                                       
                                                                  


                                   
                                                                             

                               
 
                                                                        
                                          
                                           


                                         


                 

                                                                       
 


                                                                               

                       
                                                                          

                                                                




                                                                            

 
                                                                
 
                                                                               

                          

                                                         
                                             
                                                                          

 
                                                             
 


                                                                               

 
                                                               
 
                                      
                                                            
                                                            
 
                                    

                                                        















                                                                        

                                                                  
         
                 







                                                                         

 

                                                                    
 
                                    
                                      

                            



                                                                             

                                                              
                                                                         
                                                        
                                                                           
                                                                             
                                                        
                                   
                 
                                                         



               

                                                              

                                                               
                                                                   
 
                                      

                            






                                                                          
                         
                                                         
                    


  

                                                        
                                             
   
                                                                 
                                                                
 
                                      
 



                                                                  
                    

 
                                                               


                                                                         

                             
                                             

                            


                                                    
                             




                                                                     
                                                            

                                                         

 





                                                                                
 




                                                                    
                                                           

 
  
                                               
   
                                                                
 
                                                 

 


                                               



                                         
                           
 






                                                                          

                                   
                               
 

                                          




                                          
                           
                                 
 
                                                              

                                    

                         
                        

                                                                        

                                                                           
                                                                              
                                                                        

                                                                 
         
                        
                   
                                

                                         
 

                               





                                                 
                                                    
 












                                                                          
                                       
 




                                                                    




                                                                        


                                    
 

                                                                        
                                                         
 

                                                                        


                                                             
         


                 
                                                                   
 
                                    

                                       
                            
 


                                                

                                  
 










                                                                            
 
                                    


                                                              

                                                                        



                                                                
                                        
                                                   
 

                                                              






                                                                               


         



                                                                              





                                                                          
                    
 
                                                               
                                                        
                                                                    
 

                                                                              





                                                                                
                                                                    

                                                                            
                                                                             
                                                                 



                                                                         

                                                                             



                                                         
                                               
 


                                                 


                                            
                             

             
                               


                    

                                                   
                                    
                           
                            

                                                      

                       

                                                              
 
                                                            


                                                                               
                                                       
 
                                                                   

 
                                                
 
                                             
                  
 
                                                                        
                                                                        
                                                                          
                                
                                
 
                                                                          
                                                                          
                                                                            
                                  
                                
 
                                                                               
                                                                               
                                                                                 
                                       
                                
 
                                                                       
                                                                       
                                                                         
                               
                                
 
                                                                    
                                                                    
                                                                      
                            
                                
 
                                                                   
                                                                   
                                                                     
                           
                                
 

                                                 
 

                                                                      
                                         
                                       

                              
 

                                       


                              


                                    
 


                                                            
                                                             
                    
                                                   

                                       
                             


                 

           

                                                     
                       

 
                                                  
 
                                    
                            
 
                
                       
                    

                           
 


                                            
         
                               
                                                       
 
                                                               
                               
                                                                    
 
                               
                                                          
                                                                       


                                                            
                                                          
                                                                  


                                                       
                                                          
                                                                      


                                                           
                                                          
                                                                   


                                                        
                                                          
                                                                         


                                                              
                                                          
                                                                              

                                                                   
 
                                                               
                                                                    
                                                                
 
                                          
 

                                            
                  



                                    

                                                                            
   


                                                                           
 
                                                      
                              


  

                                                                           
   


                                                                             
 
                                                      
                              


      



                                        
                                                
 
                                             



                          

                                              
 






                                                                                
 


                                                                   
 



                                                                                
 

                                                                          
 

                                                          
 
                                                     
                                           

                                             
                                                                    
 
                                                
                                                                               
                            

         
                                                                         
                                                                               
                            

         
                                                                   
                                                                            
                            

         

                                                                               
 

                                                                      
                                                                         
 

                                                                      
                                                                

                                          
                            




                 
                                                
 
                                             

                          
                           
                            
 
                                                             

                                                                                

         
                                

                                       
 


                                                                              

                                       



                                                                           
 
                                            
                                                                              
 



                                                                                
 

                                                                   
 
                                                                          
 
                                                     
                                    

                                             
                                                                    
 
                                                    
                                                 
                                                                        
                            

         
                                                                      
                                                                  
                                                                        
                            

         
                                                                   
                                                                     
                            

         






                                                                                

                                              
                 

 
                                                 
 
                                             


                          



                                        
 



                                                                              
 




                                                                                
 

                                                                    
 
                                                     
                                     

                                             
                                                                            


                             
                                                                   
                                            


                                                
                 

 
                                                    
 
                                             


                          



                                           
 




                                                                              
 




                                                                                
 

                                                                       
 
                                                     
                                        

                                             
                                                                            


                             
                                                      
                                              
                                                                           
                            

         
                                                                          
                                                                      
                                                                           
                            

         
                                                                   
                                                                        
                            

         
                                                 
                 


  

                                                                             
   
                                                    


                       
                                                    
                                                                         
                                               
                 

 
                                                         




                                                                
                                                    
                             

              


                                  
 


                                                                        
                                                                       
                                                       

                                                                 
 
                                                                           
                                                                           

                              
                                                   

                                                         
                                                                   


                                                
                                                                


                              


                                                                                



                              
                                               
 

                                                                          

                                                                          


                                                                          

                                                                 




                                                                               
 
                        


                                                                        
                                                                      


                                                                            



                                                                         
                                                    
                                                                              


                                                                            
                                            
 


                                                                        


                                                                          
                

                                                                  
                                                       
                                                       


         

                                                 








                                                                          
                                                      
 
                                             
                   
 
                                                                         
 

                                                

                                                            



                                                                         
                                                               



                                                                      
                                                        


                                                                         
 
                                                                             

                                                          
                                                  
 
                                       
                 

 
                                                         



                       
                            
 
                                     


                                       
                                            
                                                                      

                 
                                                                 
            
                                                                             





                                                      
                                                                       


                                                         
 
                 

 


                                                                  
                                                          


                                                                    
 
                                                        





                                                      
 


                                                                     
                                                                           


                                                               
                
                                                     
 
                                                             


                                                                            


                                                                       

                 


                                                              
 
                                                                

                                                                               
         
                 

 


                                                                 
 
                                                            
                                                         

                                                                   

                          
 

                                                                                
          
                                  





                                                                          




                                                              
 
                                
                                                               
                                                                  
                                                             
                                                                    
                                                              
              
                                                      
                                                               

         
                                         
                                                              


                                                  






                                                                       
                                                       
 

                                                      


                                                                        
                   

 

                                                                
 
                                             

                                          
                                                


                            
 
                                                                


                                                    
                        
                  

                                                                                
                   
                                                
                                                             
                                               
                                                     
                           
                
                  




                                                                                
                   
                                                                              

                                                                        
                                                                          
                      
                                                               
                                          

                                                                   

                                                                           



                                             


                                                         
 
                                                                      







                                                                               

                                                
                                                                
                                                                    
                                                  
         

 
                                                                         

                                                              
                                      
 

                                                             
                            
 

                                                    
 
                                       
                 

 
  

                                                                    

                                                                  
 
                                         
















                                         
                                     

 


                                                                          
 
                                    
                                           
                                       
                                     
                                                
                                      
                            
 




                                                                                
                                                        
                                           
         
                                                      
                            
                                                             
                                           
         

                                                   
                                                              



                                                                  


                              

                                                                   

                                                         
                                           

         
                                                                       

                                                                             
                                     
                               


                                                                                
 
                                                                   
                                                                  
                           
            

                                                                           
                                                                  



                                                                               



                                                                 

                            



                                                                
                                                                       
                                                                       
                                             

                                                                            
                                                                            
                         
 
                                                  

                                                                           
 
                                                
                                                        

                 
                                                                              



                                                                               
                                              



                                                                 

                
                                                                      




                                                                      
                                                               
                 

         
                  

                                                                 
                              

 



                                        


                                                                  
                                                                                
                                    
                                          
 
                                                      
                          
 
                    
 
                            
                                                                    
                          

         


                                                                                
                                         
                          
 
                                                       
                                                                      

                                            

         

                                                          
                                                                      




                                                                                
                                                 
                                                       

                                                                             

                                                       
                 
 



                               

 
                                                                          
 
                             
                                      
                            
 



                                                                     



                                                                  

                 
                                                         




               
                                                                    
   

                                                                          

                                                                       




                                          
                              
                                   
                                             
                      
 



                                                   
 
                                              
                                                                    
                      
 




                                                               
 






                                                              
 


                                                                      

         

                                                                         
                                          
                                                        



                                                                     
                                                                    
                    

 
                                                         
 
                                                                       
 


                                                                           
                        
                                
 

                                                                   
 
                                                         
                                       


                 

                                                             
                                                                       
 
                                
 

                                            

                                        
                                      
                                                           
                                         
                                                           
                                       

                                                              

                                                                             

                                                                           


                 

                                                            
                                                                 


               
  

                                                               


                                                  
                                                                                
                                      
                            
 
                                           

                                  

                                             
 
                                                                           


                                                                 



                                                                             

                         
                                                                 
 
                                                                 

         
                       




                                                             
                                                  
 
                                                                                
 
                                     
 
                                             
                                                               
                                        

         
                       

 


                                                                         

                                 
                           



                                          
                                                              

                         







                                                                            
 





                                                      



                                 


                                                    

         
                                                           
 
                                                 





                                                           




                                         
                                               




                                                   
/*
 * 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.
 *
 * You may access any attached SBP-2 (usually storage devices) as regular
 * SCSI devices. E.g. mount /dev/sda1, fdisk, mkfs, etc..
 *
 * 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.
 *
 * 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.
 */

#include <linux/blkdev.h>
#include <linux/compiler.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/gfp.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/stringify.h>
#include <linux/types.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
#include <linux/scatterlist.h>

#include <asm/byteorder.h>
#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

#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"
#include "highlevel.h"
#include "hosts.h"
#include "ieee1394.h"
#include "ieee1394_core.h"
#include "ieee1394_hotplug.h"
#include "ieee1394_transactions.h"
#include "ieee1394_types.h"
#include "nodemgr.h"
#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 2KB packets at 400mb.
 *
 * 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.
 */
static int sbp2_max_speed = IEEE1394_SPEED_MAX;
module_param_named(max_speed, sbp2_max_speed, int, 0644);
MODULE_PARM_DESC(max_speed, "Force max speed "
		 "(3 = 800Mb/s, 2 = 400Mb/s, 1 = 200Mb/s, 0 = 100Mb/s)");

/*
 * 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.
 */
static int sbp2_serialize_io = 1;
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)");

/*
 * 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 128KB, 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.
 */
static int sbp2_max_sectors;
module_param_named(max_sectors, sbp2_max_sectors, int, 0444);
MODULE_PARM_DESC(max_sectors, "Change max sectors per I/O supported "
		 "(default = 0 = use SCSI stack's default)");

/*
 * 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
 * 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.
 */
static int sbp2_exclusive_login = 1;
module_param_named(exclusive_login, sbp2_exclusive_login, bool, 0644);
MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device "
		 "(default = Y, use N for concurrent initiators)");

/*
 * 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.
 *
 * - 128kB max transfer
 *   Limit transfer size. Necessary for some old bridges.
 *
 * - 36 byte inquiry
 *   When scsi_mod probes the device, let the inquiry command look like that
 *   from MS Windows.
 *
 * - skip mode page 8
 *   Suppress sending of mode_sense for mode page 8 if the device pretends to
 *   support the SCSI Primary Block commands instead of Reduced Block Commands.
 *
 * - fix capacity
 *   Tell sd_mod to correct the last sector number reported by read_capacity.
 *   Avoids access beyond actual disk limits on devices with an off-by-one bug.
 *   Don't use this with devices which don't have this bug.
 *
 * - delay inquiry
 *   Wait extra SBP2_INQUIRY_DELAY seconds after login before SCSI inquiry.
 *
 * - 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.
 *
 * - 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.
 */
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)
	", fix capacity = "       __stringify(SBP2_WORKAROUND_FIX_CAPACITY)
	", delay inquiry = "      __stringify(SBP2_WORKAROUND_DELAY_INQUIRY)
	", set power condition in start stop unit = "
				  __stringify(SBP2_WORKAROUND_POWER_CONDITION)
	", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE)
	", or a combination)");

/*
 * This influences the format of the sysfs attribute
 * /sys/bus/scsi/devices/.../ieee1394_id.
 *
 * The default format is like in older kernels:  %016Lx:%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:  %016Lx:%06x:%04x
 * 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)");


#define SBP2_INFO(fmt, args...)	HPSB_INFO("sbp2: "fmt, ## args)
#define SBP2_ERR(fmt, args...)	HPSB_ERR("sbp2: "fmt, ## args)

/*
 * Globals
 */
static void sbp2scsi_complete_all_commands(struct sbp2_lu *, u32);
static void sbp2scsi_complete_command(struct sbp2_lu *, u32, struct scsi_cmnd *,
				      void (*)(struct scsi_cmnd *));
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 *);
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);
static int sbp2_agent_reset(struct sbp2_lu *, int);
static void sbp2_parse_unit_directory(struct sbp2_lu *,
				      struct unit_directory *);
static int sbp2_set_busy_timeout(struct sbp2_lu *);
static int sbp2_max_speed_and_size(struct sbp2_lu *);


static const u8 sbp2_speedto_max_payload[] = { 0x7, 0x8, 0x9, 0xA, 0xB, 0xC };

static DEFINE_RWLOCK(sbp2_hi_logical_units_lock);

static struct hpsb_highlevel sbp2_highlevel = {
	.name		= SBP2_DEVICE_NAME,
	.host_reset	= sbp2_host_reset,
};

static struct hpsb_address_ops sbp2_ops = {
	.write		= sbp2_handle_status_write
};

#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
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);

static struct hpsb_address_ops sbp2_physdma_ops = {
	.read		= sbp2_handle_physdma_read,
	.write		= sbp2_handle_physdma_write,
};
#endif


/*
 * Interface to driver core and IEEE 1394 core
 */
static struct ieee1394_device_id sbp2_id_table[] = {
	{
	 .match_flags	= IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
	 .specifier_id	= SBP2_UNIT_SPEC_ID_ENTRY & 0xffffff,
	 .version	= SBP2_SW_VERSION_ENTRY & 0xffffff},
	{}
};
MODULE_DEVICE_TABLE(ieee1394, sbp2_id_table);

static int sbp2_probe(struct device *);
static int sbp2_remove(struct device *);
static int sbp2_update(struct unit_directory *);

static struct hpsb_protocol_driver sbp2_driver = {
	.name		= SBP2_DEVICE_NAME,
	.id_table	= sbp2_id_table,
	.update		= sbp2_update,
	.driver		= {
		.probe		= sbp2_probe,
		.remove		= sbp2_remove,
	},
};


/*
 * 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
};

static struct scsi_host_template sbp2_shost_template = {
	.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,
};

/* for match-all entries in sbp2_workarounds_table */
#define SBP2_ROM_VALUE_WILDCARD 0x1000000

/*
 * 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.
 */
static const struct {
	u32 firmware_revision;
	u32 model_id;
	unsigned workarounds;
} sbp2_workarounds_table[] = {
	/* DViCO Momobay CX-1 with TSB42AA9 bridge */ {
		.firmware_revision	= 0x002800,
		.model_id		= 0x001010,
		.workarounds		= SBP2_WORKAROUND_INQUIRY_36 |
					  SBP2_WORKAROUND_MODE_SENSE_8 |
					  SBP2_WORKAROUND_POWER_CONDITION,
	},
	/* DViCO Momobay FX-3A with TSB42AA9A bridge */ {
		.firmware_revision	= 0x002800,
		.model_id		= 0x000000,
		.workarounds		= SBP2_WORKAROUND_DELAY_INQUIRY |
					  SBP2_WORKAROUND_POWER_CONDITION,
	},
	/* Initio bridges, actually only needed for some older ones */ {
		.firmware_revision	= 0x000200,
		.model_id		= SBP2_ROM_VALUE_WILDCARD,
		.workarounds		= SBP2_WORKAROUND_INQUIRY_36,
	},
	/* PL-3507 bridge with Prolific firmware */ {
		.firmware_revision	= 0x012800,
		.model_id		= SBP2_ROM_VALUE_WILDCARD,
		.workarounds		= SBP2_WORKAROUND_POWER_CONDITION,
	},
	/* Symbios bridge */ {
		.firmware_revision	= 0xa0b800,
		.model_id		= SBP2_ROM_VALUE_WILDCARD,
		.workarounds		= SBP2_WORKAROUND_128K_MAX_TRANS,
	},
	/* Datafab MD2-FW2 with Symbios/LSILogic SYM13FW500 bridge */ {
		.firmware_revision	= 0x002600,
		.model_id		= SBP2_ROM_VALUE_WILDCARD,
		.workarounds		= SBP2_WORKAROUND_128K_MAX_TRANS,
	},
	/* iPod 4th generation */ {
		.firmware_revision	= 0x0a2700,
		.model_id		= 0x000021,
		.workarounds		= SBP2_WORKAROUND_FIX_CAPACITY,
	},
	/* iPod mini */ {
		.firmware_revision	= 0x0a2700,
		.model_id		= 0x000022,
		.workarounds		= SBP2_WORKAROUND_FIX_CAPACITY,
	},
	/* iPod mini */ {
		.firmware_revision	= 0x0a2700,
		.model_id		= 0x000023,
		.workarounds		= SBP2_WORKAROUND_FIX_CAPACITY,
	},
	/* iPod Photo */ {
		.firmware_revision	= 0x0a2700,
		.model_id		= 0x00007e,
		.workarounds		= SBP2_WORKAROUND_FIX_CAPACITY,
	}
};

/**************************************
 * General utility functions
 **************************************/

#ifndef __BIG_ENDIAN
/*
 * Converts a buffer from be32 to cpu byte ordering. Length is in bytes.
 */
static inline void sbp2util_be32_to_cpu_buffer(void *buffer, int length)
{
	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.
 */
static inline void sbp2util_cpu_to_be32_buffer(void *buffer, int length)
{
	u32 *temp = buffer;

	for (length = (length >> 2); length--; )
		temp[length] = cpu_to_be32(temp[length]);
}
#else /* BIG_ENDIAN */
/* Why waste the cpu cycles? */
#define sbp2util_be32_to_cpu_buffer(x,y) do {} while (0)
#define sbp2util_cpu_to_be32_buffer(x,y) do {} while (0)
#endif

static DECLARE_WAIT_QUEUE_HEAD(sbp2_access_wq);

/*
 * Waits for completion of an SBP-2 access request.
 * Returns nonzero if timed out or prematurely interrupted.
 */
static int sbp2util_access_timeout(struct sbp2_lu *lu, int timeout)
{
	long leftover;

	leftover = wait_event_interruptible_timeout(
			sbp2_access_wq, lu->access_complete, timeout);
	lu->access_complete = 0;
	return leftover <= 0;
}

static void sbp2_free_packet(void *packet)
{
	hpsb_free_tlabel(packet);
	hpsb_free_packet(packet);
}

/*
 * This is much like hpsb_node_write(), except it ignores the response
 * subaction and returns immediately. Can be used from atomic context.
 */
static int sbp2util_node_write_no_wait(struct node_entry *ne, u64 addr,
				       quadlet_t *buf, size_t len)
{
	struct hpsb_packet *packet;

	packet = hpsb_make_writepacket(ne->host, ne->nodeid, addr, buf, len);
	if (!packet)
		return -ENOMEM;

	hpsb_set_packet_complete_task(packet, sbp2_free_packet, packet);
	hpsb_node_fill_packet(ne, packet);
	if (hpsb_send_packet(packet) < 0) {
		sbp2_free_packet(packet);
		return -EIO;
	}
	return 0;
}

static void sbp2util_notify_fetch_agent(struct sbp2_lu *lu, u64 offset,
					quadlet_t *data, size_t len)
{
	/* 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))
		return;

	if (hpsb_node_write(lu->ne, lu->command_block_agent_addr + offset,
			    data, len))
		SBP2_ERR("sbp2util_notify_fetch_agent failed.");

	/* 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);
}

static void sbp2util_write_orb_pointer(struct work_struct *work)
{
	struct sbp2_lu *lu = container_of(work, struct sbp2_lu, protocol_work);
	quadlet_t data[2];

	data[0] = ORB_SET_NODE_ID(lu->hi->host->node_id);
	data[1] = lu->last_orb_dma;
	sbp2util_cpu_to_be32_buffer(data, 8);
	sbp2util_notify_fetch_agent(lu, SBP2_ORB_POINTER_OFFSET, data, 8);
}

static void sbp2util_write_doorbell(struct work_struct *work)
{
	struct sbp2_lu *lu = container_of(work, struct sbp2_lu, protocol_work);

	sbp2util_notify_fetch_agent(lu, SBP2_DOORBELL_OFFSET, NULL, 4);
}

static int sbp2util_create_command_orb_pool(struct sbp2_lu *lu)
{
	struct sbp2_command_info *cmd;
	struct device *dmadev = lu->hi->host->device.parent;
	int i, orbs = sbp2_serialize_io ? 2 : SBP2_MAX_CMDS;

	for (i = 0; i < orbs; i++) {
		cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
		if (!cmd)
			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;

		INIT_LIST_HEAD(&cmd->list);
		list_add_tail(&cmd->list, &lu->cmd_orb_completed);
	}
	return 0;

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;
}

static void sbp2util_remove_command_orb_pool(struct sbp2_lu *lu,
					     struct hpsb_host *host)
{
	struct list_head *lh, *next;
	struct sbp2_command_info *cmd;
	unsigned long flags;

	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);
			dma_unmap_single(host->device.parent,
					 cmd->command_orb_dma,
					 sizeof(struct sbp2_command_orb),
					 DMA_TO_DEVICE);
			dma_unmap_single(host->device.parent, cmd->sge_dma,
					 sizeof(cmd->scatter_gather_element),
					 DMA_TO_DEVICE);
			kfree(cmd);
		}
	spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
	return;
}

/*
 * Finds the sbp2_command for a given outstanding command ORB.
 * Only looks at the in-use list.
 */
static struct sbp2_command_info *sbp2util_find_command_for_orb(
				struct sbp2_lu *lu, dma_addr_t orb)
{
	struct sbp2_command_info *cmd;
	unsigned long flags;

	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;
			}
	spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
	return NULL;
}

/*
 * Finds the sbp2_command for a given outstanding SCpnt.
 * Only looks at the in-use list.
 * Must be called with lu->cmd_orb_lock held.
 */
static struct sbp2_command_info *sbp2util_find_command_for_SCpnt(
				struct sbp2_lu *lu, void *SCpnt)
{
	struct sbp2_command_info *cmd;

	if (!list_empty(&lu->cmd_orb_inuse))
		list_for_each_entry(cmd, &lu->cmd_orb_inuse, list)
			if (cmd->Current_SCpnt == SCpnt)
				return cmd;
	return NULL;
}

static struct sbp2_command_info *sbp2util_allocate_command_orb(
				struct sbp2_lu *lu,
				struct scsi_cmnd *Current_SCpnt,
				void (*Current_done)(struct scsi_cmnd *))
{
	struct list_head *lh;
	struct sbp2_command_info *cmd = NULL;
	unsigned long flags;

	spin_lock_irqsave(&lu->cmd_orb_lock, flags);
	if (!list_empty(&lu->cmd_orb_completed)) {
		lh = lu->cmd_orb_completed.next;
		list_del(lh);
		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
		SBP2_ERR("%s: no orbs available", __func__);
	spin_unlock_irqrestore(&lu->cmd_orb_lock, flags);
	return cmd;
}

/*
 * 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)
{
	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);
	list_move_tail(&cmd->list, &lu->cmd_orb_completed);
}

/*
 * Is lu valid? Is the 1394 node still present?
 */
static inline int sbp2util_node_is_available(struct sbp2_lu *lu)
{
	return lu && lu->ne && !lu->ne->in_limbo;
}

/*********************************************
 * IEEE-1394 core driver stack related section
 *********************************************/

static int sbp2_probe(struct device *dev)
{
	struct unit_directory *ud;
	struct sbp2_lu *lu;

	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;

	lu = sbp2_alloc_device(ud);
	if (!lu)
		return -ENOMEM;

	sbp2_parse_unit_directory(lu, ud);
	return sbp2_start_device(lu);
}

static int sbp2_remove(struct device *dev)
{
	struct unit_directory *ud;
	struct sbp2_lu *lu;
	struct scsi_device *sdev;

	ud = container_of(dev, struct unit_directory, device);
	lu = ud->device.driver_data;
	if (!lu)
		return 0;

	if (lu->shost) {
		/* Get rid of enqueued commands if there is no chance to
		 * send them. */
		if (!sbp2util_node_is_available(lu))
			sbp2scsi_complete_all_commands(lu, DID_NO_CONNECT);
		/* scsi_remove_device() may trigger shutdown functions of SCSI
		 * highlevel drivers which would deadlock if blocked. */
		atomic_set(&lu->state, SBP2LU_STATE_IN_SHUTDOWN);
		scsi_unblock_requests(lu->shost);
	}
	sdev = lu->sdev;
	if (sdev) {
		lu->sdev = NULL;
		scsi_remove_device(sdev);
	}

	sbp2_logout_device(lu);
	sbp2_remove_device(lu);

	return 0;
}

static int sbp2_update(struct unit_directory *ud)
{
	struct sbp2_lu *lu = ud->device.driver_data;

	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.
		 */
		sbp2_logout_device(lu);

		if (sbp2_login_device(lu) != 0) {
			if (!hpsb_node_entry_valid(lu->ne))
				return 0;

			/* Maybe another initiator won the login. */
			SBP2_ERR("Failed to reconnect to sbp2 device!");
			return -EBUSY;
		}
	}

	sbp2_set_busy_timeout(lu);
	sbp2_agent_reset(lu, 1);
	sbp2_max_speed_and_size(lu);

	/* Complete any pending commands with busy (so they get retried)
	 * and remove them from our queue. */
	sbp2scsi_complete_all_commands(lu, DID_BUS_BUSY);

	/* Accept new commands unless there was another bus reset in the
	 * meantime. */
	if (hpsb_node_entry_valid(lu->ne)) {
		atomic_set(&lu->state, SBP2LU_STATE_RUNNING);
		scsi_unblock_requests(lu->shost);
	}
	return 0;
}