aboutsummaryrefslogblamecommitdiffstats
path: root/drivers/ieee1394/sbp2.c
blob: 12cec7c4a34295acc8e25607c7b383aedd973521 (plain) (tree)
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137


















































































                                                                                 
                                                         














                                                                          
                                                                                            




                                                                     

                                           
   
                            
                                      
                                                                                                   





































                                                                                      
                              






















                                                                              
                                    









































































































































































































































































































































































































































                                                                                                                     







                                                                                   


































                                                                                  
                                 




                                                              










                                                             













































































































                                                                                                   

                                                            









































                                                                      
                  



















































































































































                                                                                               

                                                                           
                                                   
                             
































































































































                                                                                                     
                                             















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































                                                                                                                  































































































                                                                                       







































                                                                                           
                                                                              























                                                                                                       







                                                                                           






                                                                     




















                                                                                               


































































































































































                                                                                                                               
                                          


                                            

                                                 




                                                                      
                          





                                                                        

                               









                                                                                           
                         






                                                                      

                                            









                                                                                      
                 
 



                               











































                                                                                     

































































































                                                                                            
                     


 
                                                         
 



                                                                               
 


                                                                



                 






                                                                               













                                                                                 
                                                  



































                                                                                            
                                                  


                                                                                 
                            


                                    


                                                                 



                                                              

                                                                      
                       

 




                                                            
                                                                                                        









































                                                                                    
                                                             
                                                                 
                                                               


















                                                                                       

                                                                             































                                                                           
/*
 * 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 storage devices as if they were SCSI
 * devices (e.g. mount /dev/sda1,  fdisk, mkfs, etc.).
 *
 * Current Issues:
 *
 *	- Error Handling: SCSI aborts and bus reset requests are handled somewhat
 *	  but the code needs additional debugging.
 */

#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/poll.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/blkdev.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/pci.h>

#include <asm/current.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/byteorder.h>
#include <asm/atomic.h>
#include <asm/system.h>
#include <asm/scatterlist.h>

#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 "ieee1394.h"
#include "ieee1394_types.h"
#include "ieee1394_core.h"
#include "nodemgr.h"
#include "hosts.h"
#include "highlevel.h"
#include "ieee1394_transactions.h"
#include "sbp2.h"

static char version[] __devinitdata =
	"$Rev: 1306 $ Ben Collins <bcollins@debian.org>";

/*
 * 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 max_speed = IEEE1394_SPEED_MAX;
module_param(max_speed, int, 0644);
MODULE_PARM_DESC(max_speed, "Force max speed (3 = 800mb, 2 = 400mb, 1 = 200mb, 0 = 100mb)");

/*
 * Set serialize_io to 1 if you'd like only one scsi command sent
 * down to us at a time (debugging). This might be necessary for very
 * badly behaved sbp2 devices.
 *
 * TODO: Make this configurable per device.
 */
static int serialize_io = 1;
module_param(serialize_io, int, 0444);
MODULE_PARM_DESC(serialize_io, "Serialize I/O coming from scsi drivers (default = 1, faster = 0)");

/*
 * Bump up max_sectors if you'd like to support very large sized
 * transfers. Please note that some older sbp2 bridge chips are broken for
 * transfers greater or equal to 128KB.  Default is a value of 255
 * sectors, or just under 128KB (at 512 byte sector size). I can note that
 * the Oxsemi sbp2 chipsets have no problems supporting very large
 * transfer sizes.
 */
static int max_sectors = SBP2_MAX_SECTORS;
module_param(max_sectors, int, 0444);
MODULE_PARM_DESC(max_sectors, "Change max sectors per I/O supported (default = 255)");

/*
 * 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 (one such filesystem is OpenGFS,
 * see opengfs.sourceforge.net for more info), then set exclusive_login
 * to zero. Note: The Oxsemi OXFW911 sbp2 chipset supports up to four
 * concurrent logins.
 */
static int exclusive_login = 1;
module_param(exclusive_login, int, 0644);
MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device (default = 1)");

/*
 * SCSI inquiry hack for really badly behaved sbp2 devices. Turn this on
 * if your sbp2 device is not properly handling the SCSI inquiry command.
 * This hack makes the inquiry look more like a typical MS Windows
 * inquiry.
 *
 * If force_inquiry_hack=1 is required for your device to work,
 * please submit the logged sbp2_firmware_revision value of this device to
 * the linux1394-devel mailing list.
 */
static int force_inquiry_hack;
module_param(force_inquiry_hack, int, 0444);
MODULE_PARM_DESC(force_inquiry_hack, "Force SCSI inquiry hack (default = 0)");


/*
 * Export information about protocols/devices supported by this driver.
 */
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);

/*
 * Debug levels, configured via kernel config, or enable here.
 */

#define CONFIG_IEEE1394_SBP2_DEBUG 0
/* #define CONFIG_IEEE1394_SBP2_DEBUG_ORBS */
/* #define CONFIG_IEEE1394_SBP2_DEBUG_DMA */
/* #define CONFIG_IEEE1394_SBP2_DEBUG 1 */
/* #define CONFIG_IEEE1394_SBP2_DEBUG 2 */
/* #define CONFIG_IEEE1394_SBP2_PACKET_DUMP */

#ifdef CONFIG_IEEE1394_SBP2_DEBUG_ORBS
#define SBP2_ORB_DEBUG(fmt, args...)	HPSB_ERR("sbp2(%s): "fmt, __FUNCTION__, ## args)
static u32 global_outstanding_command_orbs = 0;
#define outstanding_orb_incr global_outstanding_command_orbs++
#define outstanding_orb_decr global_outstanding_command_orbs--
#else
#define SBP2_ORB_DEBUG(fmt, args...)
#define outstanding_orb_incr
#define outstanding_orb_decr
#endif

#ifdef CONFIG_IEEE1394_SBP2_DEBUG_DMA
#define SBP2_DMA_ALLOC(fmt, args...) \
	HPSB_ERR("sbp2(%s)alloc(%d): "fmt, __FUNCTION__, \
		 ++global_outstanding_dmas, ## args)
#define SBP2_DMA_FREE(fmt, args...) \
	HPSB_ERR("sbp2(%s)free(%d): "fmt, __FUNCTION__, \
		 --global_outstanding_dmas, ## args)
static u32 global_outstanding_dmas = 0;
#else
#define SBP2_DMA_ALLOC(fmt, args...)
#define SBP2_DMA_FREE(fmt, args...)
#endif

#if CONFIG_IEEE1394_SBP2_DEBUG >= 2
#define SBP2_DEBUG(fmt, args...)	HPSB_ERR("sbp2: "fmt, ## args)
#define SBP2_INFO(fmt, args...)		HPSB_ERR("sbp2: "fmt, ## args)
#define SBP2_NOTICE(fmt, args...)	HPSB_ERR("sbp2: "fmt, ## args)
#define SBP2_WARN(fmt, args...)		HPSB_ERR("sbp2: "fmt, ## args)
#elif CONFIG_IEEE1394_SBP2_DEBUG == 1
#define SBP2_DEBUG(fmt, args...)	HPSB_DEBUG("sbp2: "fmt, ## args)
#define SBP2_INFO(fmt, args...)		HPSB_INFO("sbp2: "fmt, ## args)
#define SBP2_NOTICE(fmt, args...)	HPSB_NOTICE("sbp2: "fmt, ## args)
#define SBP2_WARN(fmt, args...)		HPSB_WARN("sbp2: "fmt, ## args)
#else
#define SBP2_DEBUG(fmt, args...)
#define SBP2_INFO(fmt, args...)		HPSB_INFO("sbp2: "fmt, ## args)
#define SBP2_NOTICE(fmt, args...)       HPSB_NOTICE("sbp2: "fmt, ## args)
#define SBP2_WARN(fmt, args...)         HPSB_WARN("sbp2: "fmt, ## args)
#endif

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


/*
 * Globals
 */

static void sbp2scsi_complete_all_commands(struct scsi_id_instance_data *scsi_id,
					   u32 status);

static void sbp2scsi_complete_command(struct scsi_id_instance_data *scsi_id,
				      u32 scsi_status, struct scsi_cmnd *SCpnt,
				      void (*done)(struct scsi_cmnd *));

static struct scsi_host_template scsi_driver_template;

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

static void sbp2_host_reset(struct hpsb_host *host);

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

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 struct hpsb_address_ops sbp2_physdma_ops = {
        .read = sbp2_handle_physdma_read,
        .write = sbp2_handle_physdma_write,
};
#endif

static struct hpsb_protocol_driver sbp2_driver = {
	.name		= "SBP2 Driver",
	.id_table	= sbp2_id_table,
	.update		= sbp2_update,
	.driver		= {
		.name		= SBP2_DEVICE_NAME,
		.bus		= &ieee1394_bus_type,
		.probe		= sbp2_probe,
		.remove		= sbp2_remove,
	},
};


/* List of device firmware's that require a forced 36 byte inquiry.  */
static u32 sbp2_broken_inquiry_list[] = {
	0x00002800,	/* Stefan Richter <richtest@bauwesen.tu-cottbus.de> */
			/* DViCO Momobay CX-1 */
	0x00000200	/* Andreas Plesch <plesch@fas.harvard.edu> */
			/* QPS Fire DVDBurner */
};

#define NUM_BROKEN_INQUIRY_DEVS \
	(sizeof(sbp2_broken_inquiry_list)/sizeof(*sbp2_broken_inquiry_list))

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

	return;
}

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

	return;
}
#else /* BIG_ENDIAN */
/* Why waste the cpu cycles? */
#define sbp2util_be32_to_cpu_buffer(x,y)
#define sbp2util_cpu_to_be32_buffer(x,y)
#endif

#ifdef CONFIG_IEEE1394_SBP2_PACKET_DUMP
/*
 * Debug packet dump routine. Length is in bytes.
 */
static void sbp2util_packet_dump(void *buffer, int length, char *dump_name, u32 dump_phys_addr)
{
	int i;
	unsigned char *dump = buffer;

	if (!dump || !length || !dump_name)
		return;

	if (dump_phys_addr)
		printk("[%s, 0x%x]", dump_name, dump_phys_addr);
	else
		printk("[%s]", dump_name);
	for (i = 0; i < length; i++) {
		if (i > 0x3f) {
			printk("\n   ...");
			break;
		}
		if ((i & 0x3) == 0)
			printk("  ");
		if ((i & 0xf) == 0)
			printk("\n   ");
		printk("%02x ", (int) dump[i]);
	}
	printk("\n");

	return;
}
#else
#define sbp2util_packet_dump(w,x,y,z)
#endif

/*
 * Goofy routine that basically does a down_timeout function.
 */
static int sbp2util_down_timeout(atomic_t *done, int timeout)
{
	int i;

	for (i = timeout; (i > 0 && atomic_read(done) == 0); i-= HZ/10) {
		if (msleep_interruptible(100))	/* 100ms */
			return(1);
	}
	return ((i > 0) ? 0:1);
}

/* Free's an allocated packet */
static void sbp2_free_packet(struct hpsb_packet *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 interrupts.
 */
static int sbp2util_node_write_no_wait(struct node_entry *ne, u64 addr,
				quadlet_t *buffer, size_t length)
{
	struct hpsb_packet *packet;

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

	hpsb_set_packet_complete_task(packet, (void (*)(void*))sbp2_free_packet,
				      packet);

	hpsb_node_fill_packet(ne, packet);

        if (hpsb_send_packet(packet) < 0) {
		sbp2_free_packet(packet);
		return -EIO;
	}

	return 0;
}

/*
 * This function is called to create a pool of command orbs used for
 * command processing. It is called when a new sbp2 device is detected.
 */
static int sbp2util_create_command_orb_pool(struct scsi_id_instance_data *scsi_id)
{
	struct sbp2scsi_host_info *hi = scsi_id->hi;
	int i;
	unsigned long flags, orbs;
	struct sbp2_command_info *command;

	orbs = serialize_io ? 2 : SBP2_MAX_CMDS;

	spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
	for (i = 0; i < orbs; i++) {
		command = (struct sbp2_command_info *)
		    kmalloc(sizeof(struct sbp2_command_info), GFP_ATOMIC);
		if (!command) {
			spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
			return(-ENOMEM);
		}
		memset(command, '\0', sizeof(struct sbp2_command_info));
		command->command_orb_dma =
			pci_map_single (hi->host->pdev, &command->command_orb,
					sizeof(struct sbp2_command_orb),
					PCI_DMA_BIDIRECTIONAL);
		SBP2_DMA_ALLOC("single command orb DMA");
		command->sge_dma =
			pci_map_single (hi->host->pdev, &command->scatter_gather_element,
					sizeof(command->scatter_gather_element),
					PCI_DMA_BIDIRECTIONAL);
		SBP2_DMA_ALLOC("scatter_gather_element");
		INIT_LIST_HEAD(&command->list);
		list_add_tail(&command->list, &scsi_id->sbp2_command_orb_completed);
	}
	spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
	return 0;
}

/*
 * This function is called to delete a pool of command orbs.
 */
static void sbp2util_remove_command_orb_pool(struct scsi_id_instance_data *scsi_id)
{
	struct hpsb_host *host = scsi_id->hi->host;
	struct list_head *lh, *next;
	struct sbp2_command_info *command;
	unsigned long flags;

	spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
	if (!list_empty(&scsi_id->sbp2_command_orb_completed)) {
		list_for_each_safe(lh, next, &scsi_id->sbp2_command_orb_completed) {
			command = list_entry(lh, struct sbp2_command_info, list);

			/* Release our generic DMA's */
			pci_unmap_single(host->pdev, command->command_orb_dma,
					 sizeof(struct sbp2_command_orb),
					 PCI_DMA_BIDIRECTIONAL);
			SBP2_DMA_FREE("single command orb DMA");
			pci_unmap_single(host->pdev, command->sge_dma,
					 sizeof(command->scatter_gather_element),
					 PCI_DMA_BIDIRECTIONAL);
			SBP2_DMA_FREE("scatter_gather_element");

			kfree(command);
		}
	}
	spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
	return;
}

/*
 * This function finds the sbp2_command for a given outstanding command
 * orb.Only looks at the inuse list.
 */
static struct sbp2_command_info *sbp2util_find_command_for_orb(
		struct scsi_id_instance_data *scsi_id, dma_addr_t orb)
{
	struct sbp2_command_info *command;
	unsigned long flags;

	spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
	if (!list_empty(&scsi_id->sbp2_command_orb_inuse)) {
		list_for_each_entry(command, &scsi_id->sbp2_command_orb_inuse, list) {
			if (command->command_orb_dma == orb) {
				spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
				return (command);
			}
		}
	}
	spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);

	SBP2_ORB_DEBUG("could not match command orb %x", (unsigned int)orb);

	return(NULL);
}

/*
 * This function finds the sbp2_command for a given outstanding SCpnt.
 * Only looks at the inuse list.
 */
static struct sbp2_command_info *sbp2util_find_command_for_SCpnt(struct scsi_id_instance_data *scsi_id, void *SCpnt)
{
	struct sbp2_command_info *command;
	unsigned long flags;

	spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
	if (!list_empty(&scsi_id->sbp2_command_orb_inuse)) {
		list_for_each_entry(command, &scsi_id->sbp2_command_orb_inuse, list) {
			if (command->Current_SCpnt == SCpnt) {
				spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
				return (command);
			}
		}
	}
	spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
	return(NULL);
}

/*
 * This function allocates a command orb used to send a scsi command.
 */
static struct sbp2_command_info *sbp2util_allocate_command_orb(
		struct scsi_id_instance_data *scsi_id,
		struct scsi_cmnd *Current_SCpnt,
		void (*Current_done)(struct scsi_cmnd *))
{
	struct list_head *lh;
	struct sbp2_command_info *command = NULL;
	unsigned long flags;

	spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
	if (!list_empty(&scsi_id->sbp2_command_orb_completed)) {
		lh = scsi_id->sbp2_command_orb_completed.next;
		list_del(lh);
		command = list_entry(lh, struct sbp2_command_info, list);
		command->Current_done = Current_done;
		command->Current_SCpnt = Current_SCpnt;
		list_add_tail(&command->list, &scsi_id->sbp2_command_orb_inuse);
	} else {
		SBP2_ERR("sbp2util_allocate_command_orb - No orbs available!");
	}
	spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
	return (command);
}

/* Free our DMA's */
static void sbp2util_free_command_dma(struct sbp2_command_info *command)
{
	struct scsi_id_instance_data *scsi_id =
		(struct scsi_id_instance_data *)command->Current_SCpnt->device->host->hostdata[0];
	struct hpsb_host *host;

	if (!scsi_id) {
		printk(KERN_ERR "%s: scsi_id == NULL\n", __FUNCTION__);
		return;
	}

	host = scsi_id->ud->ne->host;

	if (command->cmd_dma) {
		if (command->dma_type == CMD_DMA_SINGLE) {
			pci_unmap_single(host->pdev, command->cmd_dma,
					 command->dma_size, command->dma_dir);
			SBP2_DMA_FREE("single bulk");
		} else if (command->dma_type == CMD_DMA_PAGE) {
			pci_unmap_page(host->pdev, command->cmd_dma,
				       command->dma_size, command->dma_dir);
			SBP2_DMA_FREE("single page");
		} /* XXX: Check for CMD_DMA_NONE bug */
		command->dma_type = CMD_DMA_NONE;
		command->cmd_dma = 0;
	}

	if (command->sge_buffer) {
		pci_unmap_sg(host->pdev, command->sge_buffer,
			     command->dma_size, command->dma_dir);
		SBP2_DMA_FREE("scatter list");
		command->sge_buffer = NULL;
	}
}

/*
 * This function moves a command to the completed orb list.
 */
static void sbp2util_mark_command_completed(struct scsi_id_instance_data *scsi_id, struct sbp2_command_info *command)
{
	unsigned long flags;

	spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
	list_del(&command->list);
	sbp2util_free_command_dma(command);
	list_add_tail(&command->list, &scsi_id->sbp2_command_orb_completed);
	spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
}

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



/*********************************************
 * IEEE-1394 core driver stack related section
 *********************************************/
static struct scsi_id_instance_data *sbp2_alloc_device(struct unit_directory *ud);

static int sbp2_probe(struct device *dev)
{
	struct unit_directory *ud;
	struct scsi_id_instance_data *scsi_id;

	SBP2_DEBUG("sbp2_probe");

	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;

        scsi_id = sbp2_alloc_device(ud);

        if (!scsi_id)
                return -ENOMEM;

        sbp2_parse_unit_directory(scsi_id, ud);

        return sbp2_start_device(scsi_id);
}

static int sbp2_remove(struct device *dev)
{
	struct unit_directory *ud;
	struct scsi_id_instance_data *scsi_id;
	struct scsi_device *sdev;

	SBP2_DEBUG("sbp2_remove");

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

	/* Trigger shutdown functions in scsi's highlevel. */
	if (scsi_id->scsi_host)
		scsi_unblock_requests(scsi_id->scsi_host);
	sdev = scsi_id->sdev;
	if (sdev) {
		scsi_id->sdev = NULL;
		scsi_remove_device(sdev);
	}

	sbp2_logout_device(scsi_id);
	sbp2_remove_device(scsi_id);

	return 0;
}

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

	SBP2_DEBUG("sbp2_update");

	if (sbp2_reconnect_device(scsi_id)) {

		/*
		 * Ok, reconnect has failed. Perhaps we didn't
		 * reconnect fast enough. Try doing a regular login, but
		 * first do a logout just in case of any weirdness.
		 */
		sbp2_logout_device(scsi_id);

		if (sbp2_login_device(scsi_id)) {
			/* Login failed too, just fail, and the backend
			 * will call our sbp2_remove for us */
			SBP2_ERR("Failed to reconnect to sbp2 device!");
			return -EBUSY;
		}
	}

	/* Set max retries to something large on the device. */
	sbp2_set_busy_timeout(scsi_id);

	/* Do a SBP-2 fetch agent reset. */
	sbp2_agent_reset(scsi_id, 1);

	/* Get the max speed and packet size that we can use. */
	sbp2_max_speed_and_size(scsi_id);

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

	/* Make sure we unblock requests (since this is likely after a bus
	 * reset). */
	scsi_unblock_requests(scsi_id->scsi_host);

	return 0;
}

/* This functions is called by the sbp2_probe, for each new device. We now
 * allocate one scsi host for each scsi_id (unit directory). */
static struct scsi_id_instance_data *sbp2_alloc_device(struct unit_directory *ud)
{
	struct sbp2scsi_host_info *hi;
	struct Scsi_Host *scsi_host = NULL;
	struct scsi_id_instance_data *scsi_id = NULL;

	SBP2_DEBUG("sbp2_alloc_device");

	scsi_id = kmalloc(sizeof(*scsi_id), GFP_KERNEL);
	if (!scsi_id) {
		SBP2_ERR("failed to create scsi_id");
		goto failed_alloc;
	}
	memset(scsi_id, 0, sizeof(*scsi_id));

	scsi_id->ne = ud->ne;
	scsi_id->ud = ud;
	scsi_id->speed_code = IEEE1394_SPEED_100;
	scsi_id->max_payload_size = sbp2_speedto_max_payload[IEEE1394_SPEED_100];
	atomic_set(&scsi_id->sbp2_login_complete, 0);
	INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_inuse);
	INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_completed);
	INIT_LIST_HEAD(&scsi_id->scsi_list);
	spin_lock_init(&scsi_id->sbp2_command_orb_lock);
	scsi_id->sbp2_device_type_and_lun = SBP2_DEVICE_TYPE_LUN_UNINITIALIZED;

	ud->device.driver_data = scsi_id;

	hi = hpsb_get_hostinfo(&sbp2_highlevel, ud->ne->host);
	if (!hi) {
		hi = hpsb_create_hostinfo(&sbp2_highlevel, ud->ne->host, sizeof(*hi));
		if (!hi) {
			SBP2_ERR("failed to allocate hostinfo");
			goto failed_alloc;
		}
		SBP2_DEBUG("sbp2_alloc_device: allocated hostinfo");
		hi->host = ud->ne->host;
		INIT_LIST_HEAD(&hi->scsi_ids);

		/* Register our sbp2 status address space... */
		hpsb_register_addrspace(&sbp2_highlevel, ud->ne->host, &sbp2_ops,
					SBP2_STATUS_FIFO_ADDRESS,
					SBP2_STATUS_FIFO_ADDRESS +
					SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(SBP2_MAX_UDS_PER_NODE+1));
#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
		/* Handle data movement if physical dma is not
		 * enabled/supportedon host controller */
		hpsb_register_addrspace(&sbp2_highlevel, ud->ne->host, &sbp2_physdma_ops,
					0x0ULL, 0xfffffffcULL);
#endif
	}

	scsi_id->hi = hi;

	list_add_tail(&scsi_id->scsi_list, &hi->scsi_ids);

	/* Register our host with the SCSI stack. */
	scsi_host = scsi_host_alloc(&scsi_driver_template,
				    sizeof (unsigned long));
	if (!scsi_host) {
		SBP2_ERR("failed to register scsi host");
		goto failed_alloc;
	}

	scsi_host->hostdata[0] = (unsigned long)scsi_id;

	if (!scsi_add_host(scsi_host, &ud->device)) {
		scsi_id->scsi_host = scsi_host;
		return scsi_id;
	}

	SBP2_ERR("failed to add scsi host");
	scsi_host_put(scsi_host);

failed_alloc:
	sbp2_remove_device(scsi_id);
	return NULL;
}


static void sbp2_host_reset(struct hpsb_host *host)
{
	struct sbp2scsi_host_info *hi;
	struct scsi_id_instance_data *scsi_id;

	hi = hpsb_get_hostinfo(&sbp2_highlevel, host);

	if (hi) {
		list_for_each_entry(scsi_id, &hi->scsi_ids, scsi_list)
			scsi_block_requests(scsi_id->scsi_host);
	}
}


/*
 * This function is where we first pull the node unique ids, and then
 * allocate memory and register a SBP-2 device.
 */
static int sbp2_start_device(struct scsi_id_instance_data *scsi_id)
{
	struct sbp2scsi_host_info *hi = scsi_id->hi;
	int error;

	SBP2_DEBUG("sbp2_start_device");

	/* Login FIFO DMA */
	scsi_id->login_response =
		pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_login_response),
				     &scsi_id->login_response_dma);
	if (!scsi_id->login_response)
		goto alloc_fail;
	SBP2_DMA_ALLOC("consistent DMA region for login FIFO");

	/* Query logins ORB DMA */
	scsi_id->query_logins_orb =
		pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_query_logins_orb),
				     &scsi_id->query_logins_orb_dma);
	if (!scsi_id->query_logins_orb)
		goto alloc_fail;
	SBP2_DMA_ALLOC("consistent DMA region for query logins ORB");

	/* Query logins response DMA */
	scsi_id->query_logins_response =
		pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_query_logins_response),
				     &scsi_id->query_logins_response_dma);
	if (!scsi_id->query_logins_response)
		goto alloc_fail;
	SBP2_DMA_ALLOC("consistent DMA region for query logins response");

	/* Reconnect ORB DMA */
	scsi_id->reconnect_orb =
		pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_reconnect_orb),
				     &scsi_id->reconnect_orb_dma);
	if (!scsi_id->reconnect_orb)
		goto alloc_fail;
	SBP2_DMA_ALLOC("consistent DMA region for reconnect ORB");

	/* Logout ORB DMA */
	scsi_id->logout_orb =
		pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_logout_orb),
				     &scsi_id->logout_orb_dma);
	if (!scsi_id->logout_orb)
		goto alloc_fail;
	SBP2_DMA_ALLOC("consistent DMA region for logout ORB");

	/* Login ORB DMA */
	scsi_id->login_orb =
		pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_login_orb),
				     &scsi_id->login_orb_dma);
	if (!scsi_id->login_orb) {
alloc_fail:
		if (scsi_id->query_logins_response) {
			pci_free_consistent(hi->host->pdev,
					    sizeof(struct sbp2_query_logins_response),
					    scsi_id->query_logins_response,
					    scsi_id->query_logins_response_dma);
			SBP2_DMA_FREE("query logins response DMA");
		}

		if (scsi_id->query_logins_orb) {
			pci_free_consistent(hi->host->pdev,
					    sizeof(struct sbp2_query_logins_orb),
					    scsi_id->query_logins_orb,
					    scsi_id->query_logins_orb_dma);
			SBP2_DMA_FREE("query logins ORB DMA");
		}

		if (scsi_id->logout_orb) {
			pci_free_consistent(hi->host->pdev,
					sizeof(struct sbp2_logout_orb),
					scsi_id->logout_orb,
					scsi_id->logout_orb_dma);
			SBP2_DMA_FREE("logout ORB DMA");
		}

		if (scsi_id->reconnect_orb) {
			pci_free_consistent(hi->host->pdev,
					sizeof(struct sbp2_reconnect_orb),
					scsi_id->reconnect_orb,
					scsi_id->reconnect_orb_dma);
			SBP2_DMA_FREE("reconnect ORB DMA");
		}

		if (scsi_id->login_response) {
			pci_free_consistent(hi->host->pdev,
					sizeof(struct sbp2_login_response),
					scsi_id->login_response,
					scsi_id->login_response_dma);
			SBP2_DMA_FREE("login FIFO DMA");
		}

		list_del(&scsi_id->scsi_list);

		kfree(scsi_id);

		SBP2_ERR ("Could not allocate memory for scsi_id");

		return -ENOMEM;
	}
	SBP2_DMA_ALLOC("consistent DMA region for login ORB");

	SBP2_DEBUG("New SBP-2 device inserted, SCSI ID = %x", scsi_id->ud->id);

	/*
	 * Create our command orb pool
	 */
	if (sbp2util_create_command_orb_pool(scsi_id)) {
		SBP2_ERR("sbp2util_create_command_orb_pool failed!");
		sbp2_remove_device(scsi_id);
		return -ENOMEM;
	}

	/* Schedule a timeout here. The reason is that we may be so close
	 * to a bus reset, that the device is not available for logins.
	 * This can happen when the bus reset is caused by the host
	 * connected to the sbp2 device being removed. That host would
	 * have a certain amount of time to relogin before the sbp2 device
	 * allows someone else to login instead. One second makes sense. */
	msleep_interruptible(1000);
	if (signal_pending(current)) {
		SBP2_WARN("aborting sbp2_start_device due to event");
		sbp2_remove_device(scsi_id);
		return -EINTR;
	}
	
	/*
	 * Login to the sbp-2 device
	 */
	if (sbp2_login_device(scsi_id)) {
		/* Login failed, just remove the device. */
		sbp2_remove_device(scsi_id);
		return -EBUSY;
	}

	/*
	 * Set max retries to something large on the device
	 */
	sbp2_set_busy_timeout(scsi_id);

	/*
	 * Do a SBP-2 fetch agent reset
	 */
	sbp2_agent_reset(scsi_id, 1);

	/*
	 * Get the max speed and packet size that we can use
	 */
	sbp2_max_speed_and_size(scsi_id);

	/* Add this device to the scsi layer now */
	error = scsi_add_device(scsi_id->scsi_host, 0, scsi_id->ud->id, 0);
	if (error) {
		SBP2_ERR("scsi_add_device failed");
		return error;
	}

	return 0;
}

/*
 * This function removes an sbp2 device from the sbp2scsi_host_info struct.
 */
static void sbp2_remove_device(struct scsi_id_instance_data *scsi_id)
{
	struct sbp2scsi_host_info *hi;

	SBP2_DEBUG("sbp2_remove_device");

	if (!scsi_id)
		return;

	hi = scsi_id->hi;

	/* This will remove our scsi device aswell */
	if (scsi_id->scsi_host) {
		scsi_remove_host(scsi_id->scsi_host);
		scsi_host_put(scsi_id->scsi_host);
	}

	sbp2util_remove_command_orb_pool(scsi_id);

	list_del(&scsi_id->scsi_list);

	if (scsi_id->login_response) {
		pci_free_consistent(hi->host->pdev,
				    sizeof(struct sbp2_login_response),
				    scsi_id->login_response,
				    scsi_id->login_response_dma);
		SBP2_DMA_FREE("single login FIFO");
	}

	if (scsi_id->login_orb) {
		pci_free_consistent(hi->host->pdev,
				    sizeof(struct sbp2_login_orb),
				    scsi_id->login_orb,
				    scsi_id->login_orb_dma);
		SBP2_DMA_FREE("single login ORB");
	}

	if (scsi_id->reconnect_orb) {
		pci_free_consistent(hi->host->pdev,
				    sizeof(struct sbp2_reconnect_orb),
				    scsi_id->reconnect_orb,
				    scsi_id->reconnect_orb_dma);
		SBP2_DMA_FREE("single reconnect orb");
	}

	if (scsi_id->logout_orb) {
		pci_free_consistent(hi->host->pdev,
				    sizeof(struct sbp2_logout_orb),
				    scsi_id->logout_orb,
				    scsi_id->logout_orb_dma);
		SBP2_DMA_FREE("single logout orb");
	}

	if (scsi_id->query_logins_orb) {
		pci_free_consistent(hi->host->pdev,
				    sizeof(struct sbp2_query_logins_orb),
				    scsi_id->query_logins_orb,
				    scsi_id->query_logins_orb_dma);
		SBP2_DMA_FREE("single query logins orb");
	}

	if (scsi_id->query_logins_response) {
		pci_free_consistent(hi->host->pdev,
				    sizeof(struct sbp2_query_logins_response),
				    scsi_id->query_logins_response,
				    scsi_id->query_logins_response_dma);
		SBP2_DMA_FREE("single query logins data");
	}

	scsi_id->ud->device.driver_data = NULL;

	SBP2_DEBUG("SBP-2 device removed, SCSI ID = %d", scsi_id->ud->id);

	kfree(scsi_id);
}

#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
/*
 * This function deals with physical dma write requests (for adapters that do not support
 * physical dma in hardware). Mostly just here for debugging...
 */
static int sbp2_handle_physdma_write(struct hpsb_host *host, int nodeid, int destid, quadlet_t *data,
                                     u64 addr, size_t length, u16 flags)
{

        /*
         * Manually put the data in the right place.
         */
        memcpy(bus_to_virt((u32)addr), data, length);
	sbp2util_packet_dump(data, length, "sbp2 phys dma write by device", (u32)addr);
        return(RCODE_COMPLETE);
}

/*
 * This function deals with physical dma read requests (for adapters that do not support
 * physical dma in hardware). Mostly just here for debugging...
 */
static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid, quadlet_t *data,
                                    u64 addr, size_t length, u16 flags)
{

        /*
         * Grab data from memory and send a read response.
         */
        memcpy(data, bus_to_virt((u32)addr), length);
	sbp2util_packet_dump(data, length, "sbp2 phys dma read by device", (u32)addr);
        return(RCODE_COMPLETE);
}
#endif


/**************************************
 * SBP-2 protocol related section
 **************************************/

/*
 * This function determines if we should convert scsi commands for a particular sbp2 device type
 */
static __inline__ int sbp2_command_conversion_device_type(u8 device_type)
{
	return (((device_type == TYPE_DISK) ||
		 (device_type == TYPE_RBC) ||
		 (device_type == TYPE_ROM)) ? 1:0);
}

/*
 * This function queries the device for the maximum concurrent logins it
 * supports.
 */
static int sbp2_query_logins(struct scsi_id_instance_data *scsi_id)
{
	struct sbp2scsi_host_info *hi = scsi_id->hi;
	quadlet_t data[2];
	int max_logins;
	int active_logins;

	SBP2_DEBUG("sbp2_query_logins");

	scsi_id->query_logins_orb->reserved1 = 0x0;
	scsi_id->query_logins_orb->reserved2 = 0x0;

	scsi_id->query_logins_orb->query_response_lo = scsi_id->query_logins_response_dma;
	scsi_id->query_logins_orb->query_response_hi = ORB_SET_NODE_ID(hi->host->node_id);
	SBP2_DEBUG("sbp2_query_logins: query_response_hi/lo initialized");

	scsi_id->query_logins_orb->lun_misc = ORB_SET_FUNCTION(SBP2_QUERY_LOGINS_REQUEST);
	scsi_id->query_logins_orb->lun_misc |= ORB_SET_NOTIFY(1);
	if (scsi_id->sbp2_device_type_and_lun != SBP2_DEVICE_TYPE_LUN_UNINITIALIZED) {
		scsi_id->query_logins_orb->lun_misc |= ORB_SET_LUN(scsi_id->sbp2_device_type_and_lun);
		SBP2_DEBUG("sbp2_query_logins: set lun to %d",
			   ORB_SET_LUN(scsi_id->sbp2_device_type_and_lun));
	}
	SBP2_DEBUG("sbp2_query_logins: lun_misc initialized");

	scsi_id->query_logins_orb->reserved_resp_length =
		ORB_SET_QUERY_LOGINS_RESP_LENGTH(sizeof(struct sbp2_query_logins_response));
	SBP2_DEBUG("sbp2_query_logins: reserved_resp_length initialized");

	scsi_id->query_logins_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO +
						    SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(scsi_id->ud->id);
	scsi_id->query_logins_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) |
						     SBP2_STATUS_FIFO_ADDRESS_HI);
	SBP2_DEBUG("sbp2_query_logins: status FIFO initialized");

	sbp2util_cpu_to_be32_buffer(scsi_id->query_logins_orb, sizeof(struct sbp2_query_logins_orb));

	SBP2_DEBUG("sbp2_query_logins: orb byte-swapped");

	sbp2util_packet_dump(scsi_id->query_logins_orb, sizeof(struct sbp2_query_logins_orb),
			     "sbp2 query logins orb", scsi_id->query_logins_orb_dma);

	memset(scsi_id->query_logins_response, 0, sizeof(struct sbp2_query_logins_response));
	memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block));

	SBP2_DEBUG("sbp2_query_logins: query_logins_response/status FIFO memset");

	data[0] = ORB_SET_NODE_ID(hi->host->node_id);
	data[1] = scsi_id->query_logins_orb_dma;
	sbp2util_cpu_to_be32_buffer(data, 8);

	atomic_set(&scsi_id->sbp2_login_complete, 0);

	SBP2_DEBUG("sbp2_query_logins: prepared to write");
	hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8);
	SBP2_DEBUG("sbp2_query_logins: written");

	if (sbp2util_down_timeout(&scsi_id->sbp2_login_complete, 2*HZ)) {
		SBP2_INFO("Error querying logins to SBP-2 device - timed out");
		return(-EIO);
	}

	if (scsi_id->status_block.ORB_offset_lo != scsi_id->query_logins_orb_dma) {
		SBP2_INFO("Error querying logins to SBP-2 device - timed out");
		return(-EIO);
	}

	if (STATUS_GET_RESP(scsi_id->status_block.ORB_offset_hi_misc) ||
	    STATUS_GET_DEAD_BIT(scsi_id->status_block.ORB_offset_hi_misc) ||
	    STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc)) {

		SBP2_INFO("Error querying logins to SBP-2 device - timed out");
		return(-EIO);
	}

	sbp2util_cpu_to_be32_buffer(scsi_id->query_logins_response, sizeof(struct sbp2_query_logins_response));

	SBP2_DEBUG("length_max_logins = %x",
		   (unsigned int)scsi_id->query_logins_response->length_max_logins);

	SBP2_DEBUG("Query logins to SBP-2 device successful");

	max_logins = RESPONSE_GET_MAX_LOGINS(scsi_id->query_logins_response->length_max_logins);
	SBP2_DEBUG("Maximum concurrent logins supported: %d", max_logins);

	active_logins = RESPONSE_GET_ACTIVE_LOGINS(scsi_id->query_logins_response->length_max_logins);
	SBP2_DEBUG("Number of active logins: %d", active_logins);

	if (active_logins >= max_logins) {
		return(-EIO);
	}

	return 0;
}

/*
 * This function is called in order to login to a particular SBP-2 device,
 * after a bus reset.
 */
static int sbp2_login_device(struct scsi_id_instance_data *scsi_id)
{
	struct sbp2scsi_host_info *hi = scsi_id->hi;
	quadlet_t data[2];

	SBP2_DEBUG("sbp2_login_device");

	if (!scsi_id->login_orb) {
		SBP2_DEBUG("sbp2_login_device: login_orb not alloc'd!");
		return(-EIO);
	}

	if (!exclusive_login) {
		if (sbp2_query_logins(scsi_id)) {
			SBP2_INFO("Device does not support any more concurrent logins");
			return(-EIO);
		}
	}

	/* Set-up login ORB, assume no password */
	scsi_id->login_orb->password_hi = 0;
	scsi_id->login_orb->password_lo = 0;
	SBP2_DEBUG("sbp2_login_device: password_hi/lo initialized");

	scsi_id->login_orb->login_response_lo = scsi_id->login_response_dma;
	scsi_id->login_orb->login_response_hi = ORB_SET_NODE_ID(hi->host->node_id);
	SBP2_DEBUG("sbp2_login_device: login_response_hi/lo initialized");

	scsi_id->login_orb->lun_misc = ORB_SET_FUNCTION(SBP2_LOGIN_REQUEST);
	scsi_id->login_orb->lun_misc |= ORB_SET_RECONNECT(0);	/* One second reconnect time */
	scsi_id->login_orb->lun_misc |= ORB_SET_EXCLUSIVE(exclusive_login);	/* Exclusive access to device */
	scsi_id->login_orb->lun_misc |= ORB_SET_NOTIFY(1);	/* Notify us of login complete */
	/* Set the lun if we were able to pull it from the device's unit directory */
	if (scsi_id->sbp2_device_type_and_lun != SBP2_DEVICE_TYPE_LUN_UNINITIALIZED) {
		scsi_id->login_orb->lun_misc |= ORB_SET_LUN(scsi_id->sbp2_device_type_and_lun);
		SBP2_DEBUG("sbp2_query_logins: set lun to %d",
			   ORB_SET_LUN(scsi_id->sbp2_device_type_and_lun));
	}
	SBP2_DEBUG("sbp2_login_device: lun_misc initialized");

	scsi_id->login_orb->passwd_resp_lengths =
		ORB_SET_LOGIN_RESP_LENGTH(sizeof(struct sbp2_login_response));
	SBP2_DEBUG("sbp2_login_device: passwd_resp_lengths initialized");

	scsi_id->login_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO +
					     SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(scsi_id->ud->id);
	scsi_id->login_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) |
					      SBP2_STATUS_FIFO_ADDRESS_HI);
	SBP2_DEBUG("sbp2_login_device: status FIFO initialized");

	/*
	 * Byte swap ORB if necessary
	 */
	sbp2util_cpu_to_be32_buffer(scsi_id->login_orb, sizeof(struct sbp2_login_orb));

	SBP2_DEBUG("sbp2_login_device: orb byte-swapped");

	sbp2util_packet_dump(scsi_id->login_orb, sizeof(struct sbp2_login_orb),
			     "sbp2 login orb", scsi_id->login_orb_dma);

	/*
	 * Initialize login response and status fifo
	 */
	memset(scsi_id->login_response, 0, sizeof(struct sbp2_login_response));
	memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block));

	SBP2_DEBUG("sbp2_login_device: login_response/status FIFO memset");

	/*
	 * Ok, let's write to the target's management agent register
	 */
	data[0] = ORB_SET_NODE_ID(hi->host->node_id);
	data[1] = scsi_id->login_orb_dma;
	sbp2util_cpu_to_be32_buffer(data, 8);

	atomic_set(&scsi_id->sbp2_login_complete, 0);

	SBP2_DEBUG("sbp2_login_device: prepared to write to %08x",
		   (unsigned int)scsi_id->sbp2_management_agent_addr);
	hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8);
	SBP2_DEBUG("sbp2_login_device: written");

	/*
	 * Wait for login status (up to 20 seconds)...
	 */
	if (sbp2util_down_timeout(&scsi_id->sbp2_login_complete, 20*HZ)) {
		SBP2_ERR("Error logging into SBP-2 device - login timed-out");
		return(-EIO);
	}

	/*
	 * Sanity. Make sure status returned matches login orb.
	 */
	if (scsi_id->status_block.ORB_offset_lo != scsi_id->login_orb_dma) {
		SBP2_ERR("Error logging into SBP-2 device - login timed-out");
		return(-EIO);
	}

	/*
	 * Check status
	 */
	if (STATUS_GET_RESP(scsi_id->status_block.ORB_offset_hi_misc) ||
	    STATUS_GET_DEAD_BIT(scsi_id->status_block.ORB_offset_hi_misc) ||
	    STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc)) {

		SBP2_ERR("Error logging into SBP-2 device - login failed");
		return(-EIO);
	}

	/*
	 * Byte swap the login response, for use when reconnecting or
	 * logging out.
	 */
	sbp2util_cpu_to_be32_buffer(scsi_id->login_response, sizeof(struct sbp2_login_response));

	/*
	 * Grab our command block agent address from the login response.
	 */
	SBP2_DEBUG("command_block_agent_hi = %x",
		   (unsigned int)scsi_id->login_response->command_block_agent_hi);
	SBP2_DEBUG("command_block_agent_lo = %x",
		   (unsigned int)scsi_id->login_response->command_block_agent_lo);

	scsi_id->sbp2_command_block_agent_addr =
		((u64)scsi_id->login_response->command_block_agent_hi) << 32;
	scsi_id->sbp2_command_block_agent_addr |= ((u64)scsi_id->login_response->command_block_agent_lo);
	scsi_id->sbp2_command_block_agent_addr &= 0x0000ffffffffffffULL;

	SBP2_INFO("Logged into SBP-2 device");

	return(0);

}

/*
 * This function is called in order to logout from a particular SBP-2
 * device, usually called during driver unload.
 */
static int sbp2_logout_device(struct scsi_id_instance_data *scsi_id)
{
	struct sbp2scsi_host_info *hi = scsi_id->hi;
	quadlet_t data[2];
	int error;

	SBP2_DEBUG("sbp2_logout_device");

	/*
	 * Set-up logout ORB
	 */
	scsi_id->logout_orb->reserved1 = 0x0;
	scsi_id->logout_orb->reserved2 = 0x0;
	scsi_id->logout_orb->reserved3 = 0x0;
	scsi_id->logout_orb->reserved4 = 0x0;

	scsi_id->logout_orb->login_ID_misc = ORB_SET_FUNCTION(SBP2_LOGOUT_REQUEST);
	scsi_id->logout_orb->login_ID_misc |= ORB_SET_LOGIN_ID(scsi_id->login_response->length_login_ID);

	/* Notify us when complete */
	scsi_id->logout_orb->login_ID_misc |= ORB_SET_NOTIFY(1);

	scsi_id->logout_orb->reserved5 = 0x0;
	scsi_id->logout_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO +
					      SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(scsi_id->ud->id);
	scsi_id->logout_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) |
					       SBP2_STATUS_FIFO_ADDRESS_HI);

	/*
	 * Byte swap ORB if necessary
	 */
	sbp2util_cpu_to_be32_buffer(scsi_id->logout_orb, sizeof(struct sbp2_logout_orb));

	sbp2util_packet_dump(scsi_id->logout_orb, sizeof(struct sbp2_logout_orb),
			     "sbp2 logout orb", scsi_id->logout_orb_dma);

	/*
	 * Ok, let's write to the target's management agent register
	 */
	data[0] = ORB_SET_NODE_ID(hi->host->node_id);
	data[1] = scsi_id->logout_orb_dma;
	sbp2util_cpu_to_be32_buffer(data, 8);

	atomic_set(&scsi_id->sbp2_login_complete, 0);

	error = hpsb_node_write(scsi_id->ne,
	                            scsi_id->sbp2_management_agent_addr,
	                            data, 8);
	if (error)
		return error;

	/* Wait for device to logout...1 second. */
	if (sbp2util_down_timeout(&scsi_id->sbp2_login_complete, HZ))
		return -EIO;

	SBP2_INFO("Logged out of SBP-2 device");

	return(0);

}

/*
 * This function is called in order to reconnect to a particular SBP-2
 * device, after a bus reset.
 */
static int sbp2_reconnect_device(struct scsi_id_instance_data *scsi_id)
{
	struct sbp2scsi_host_info *hi = scsi_id->hi;
	quadlet_t data[2];
	int error;

	SBP2_DEBUG("sbp2_reconnect_device");

	/*
	 * Set-up reconnect ORB
	 */
	scsi_id->reconnect_orb->reserved1 = 0x0;
	scsi_id->reconnect_orb->reserved2 = 0x0;
	scsi_id->reconnect_orb->reserved3 = 0x0;
	scsi_id->reconnect_orb->reserved4 = 0x0;

	scsi_id->reconnect_orb->login_ID_misc = ORB_SET_FUNCTION(SBP2_RECONNECT_REQUEST);
	scsi_id->reconnect_orb->login_ID_misc |=
		ORB_SET_LOGIN_ID(scsi_id->login_response->length_login_ID);

	/* Notify us when complete */
	scsi_id->reconnect_orb->login_ID_misc |= ORB_SET_NOTIFY(1);

	scsi_id->reconnect_orb->reserved5 = 0x0;
	scsi_id->reconnect_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO +
						 SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(scsi_id->ud->id);
	scsi_id->reconnect_orb->status_FIFO_hi =
		(ORB_SET_NODE_ID(hi->host->node_id) | SBP2_STATUS_FIFO_ADDRESS_HI);

	/*
	 * Byte swap ORB if necessary
	 */
	sbp2util_cpu_to_be32_buffer(scsi_id->reconnect_orb, sizeof(struct sbp2_reconnect_orb));

	sbp2util_packet_dump(scsi_id->reconnect_orb, sizeof(struct sbp2_reconnect_orb),
			     "sbp2 reconnect orb", scsi_id->reconnect_orb_dma);

	/*
	 * Initialize status fifo
	 */
	memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block));

	/*
	 * Ok, let's write to the target's management agent register
	 */
	data[0] = ORB_SET_NODE_ID(hi->host->node_id);
	data[1] = scsi_id->reconnect_orb_dma;
	sbp2util_cpu_to_be32_buffer(data, 8);

	atomic_set(&scsi_id->sbp2_login_complete, 0);

	error = hpsb_node_write(scsi_id->ne,
	                            scsi_id->sbp2_management_agent_addr,
	                            data, 8);
	if (error)
		return error;

	/*
	 * Wait for reconnect status (up to 1 second)...
	 */
	if (sbp2util_down_timeout(&scsi_id->sbp2_login_complete, HZ)) {
		SBP2_ERR("Error reconnecting to SBP-2 device - reconnect timed-out");
		return(-EIO);
	}

	/*
	 * Sanity. Make sure status returned matches reconnect orb.
	 */
	if (scsi_id->status_block.ORB_offset_lo != scsi_id->reconnect_orb_dma) {
		SBP2_ERR("Error reconnecting to SBP-2 device - reconnect timed-out");
		return(-EIO);
	}

	/*
	 * Check status
	 */
	if (STATUS_GET_RESP(scsi_id->status_block.ORB_offset_hi_misc) ||
	    STATUS_GET_DEAD_BIT(scsi_id->status_block.ORB_offset_hi_misc) ||
	    STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc)) {

		SBP2_ERR("Error reconnecting to SBP-2 device - reconnect failed");
		return(-EIO);
	}

	HPSB_DEBUG("Reconnected to SBP-2 device");

	return(0);

}

/*
 * This function is called in order to set the busy timeout (number of
 * retries to attempt) on the sbp2 device.
 */
static int sbp2_set_busy_timeout(struct scsi_id_instance_data *scsi_id)
{
	quadlet_t data;

	SBP2_DEBUG("sbp2_set_busy_timeout");

	/*
	 * Ok, let's write to the target's busy timeout register
	 */
	data = cpu_to_be32(SBP2_BUSY_TIMEOUT_VALUE);

	if (hpsb_node_write(scsi_id->ne, SBP2_BUSY_TIMEOUT_ADDRESS, &data, 4)) {
		SBP2_ERR("sbp2_set_busy_timeout error");
	}

	return(0);
}


/*
 * This function is called to parse sbp2 device's config rom unit
 * directory. Used to determine things like sbp2 management agent offset,
 * and command set used (SCSI or RBC).
 */
static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id,
				      struct unit_directory *ud)
{
	struct csr1212_keyval *kv;
	struct csr1212_dentry *dentry;
	u64 management_agent_addr;
	u32 command_set_spec_id, command_set, unit_characteristics,
		firmware_revision, workarounds;
	int i;

	SBP2_DEBUG("sbp2_parse_unit_directory");

	management_agent_addr = 0x0;
	command_set_spec_id = 0x0;
	command_set = 0x0;
	unit_characteristics = 0x0;
	firmware_revision = 0x0;

	/* Handle different fields in the unit directory, based on keys */
	csr1212_for_each_dir_entry(ud->ne->csr, kv, ud->ud_kv, dentry) {
		switch (kv->key.id) {
		case CSR1212_KV_ID_DEPENDENT_INFO:
			if (kv->key.type == CSR1212_KV_TYPE_CSR_OFFSET) {
				/* Save off the management agent address */
				management_agent_addr =
					CSR1212_REGISTER_SPACE_BASE +
					(kv->value.csr_offset << 2);

				SBP2_DEBUG("sbp2_management_agent_addr = %x",
					   (unsigned int) management_agent_addr);
			} else if (kv->key.type == CSR1212_KV_TYPE_IMMEDIATE) {
				scsi_id->sbp2_device_type_and_lun = kv->value.immediate;
			}
			break;

		case SBP2_COMMAND_SET_SPEC_ID_KEY:
			/* Command spec organization */
			command_set_spec_id = kv->value.immediate;
			SBP2_DEBUG("sbp2_command_set_spec_id = %x",
				   (unsigned int) command_set_spec_id);
			break;

		case SBP2_COMMAND_SET_KEY:
			/* Command set used by sbp2 device */
			command_set = kv->value.immediate;
			SBP2_DEBUG("sbp2_command_set = %x",
				   (unsigned int) command_set);
			break;

		case SBP2_UNIT_CHARACTERISTICS_KEY:
			/*
			 * Unit characterisitcs (orb related stuff
			 * that I'm not yet paying attention to)
			 */
			unit_characteristics = kv->value.immediate;
			SBP2_DEBUG("sbp2_unit_characteristics = %x",
				   (unsigned int) unit_characteristics);
			break;

		case SBP2_FIRMWARE_REVISION_KEY:
			/* Firmware revision */
			firmware_revision = kv->value.immediate;
			if (force_inquiry_hack)
				SBP2_INFO("sbp2_firmware_revision = %x",
				   (unsigned int) firmware_revision);
			else	SBP2_DEBUG("sbp2_firmware_revision = %x",
				   (unsigned int) firmware_revision);
			break;

		default:
			break;
		}
	}

	/* This is the start of our broken device checking. We try to hack
	 * around oddities and known defects.  */
	workarounds = 0x0;

	/* If the vendor id is 0xa0b8 (Symbios vendor id), then we have a
	 * bridge with 128KB max transfer size limitation. For sanity, we
	 * only voice this when the current max_sectors setting
	 * exceeds the 128k limit. By default, that is not the case.
	 *
	 * It would be really nice if we could detect this before the scsi
	 * host gets initialized. That way we can down-force the
	 * max_sectors to account for it. That is not currently
	 * possible.  */
	if ((firmware_revision & 0xffff00) ==
			SBP2_128KB_BROKEN_FIRMWARE &&
			(max_sectors * 512) > (128*1024)) {
		SBP2_WARN("Node " NODE_BUS_FMT ": Bridge only supports 128KB max transfer size.",
				NODE_BUS_ARGS(ud->ne->host, ud->ne->nodeid));
		SBP2_WARN("WARNING: Current max_sectors setting is larger than 128KB (%d sectors)!",
				max_sectors);
		workarounds |= SBP2_BREAKAGE_128K_MAX_TRANSFER;
	}

	/* Check for a blacklisted set of devices that require us to force
	 * a 36 byte host inquiry. This can be overriden as a module param
	 * (to force all hosts).  */
	for (i = 0; i < NUM_BROKEN_INQUIRY_DEVS; i++) {
		if ((firmware_revision & 0xffff00) ==
				sbp2_broken_inquiry_list[i]) {
			SBP2_WARN("Node " NODE_BUS_FMT ": Using 36byte inquiry workaround",
					NODE_BUS_ARGS(ud->ne->host, ud->ne->nodeid));
			workarounds |= SBP2_BREAKAGE_INQUIRY_HACK;
			break; /* No need to continue. */
		}
	}

	/* If this is a logical unit directory entry, process the parent
	 * to get the values. */
	if (ud->flags & UNIT_DIRECTORY_LUN_DIRECTORY) {
		struct unit_directory *parent_ud =
			container_of(ud->device.parent, struct unit_directory, device);
		sbp2_parse_unit_directory(scsi_id, parent_ud);
	} else {
		scsi_id->sbp2_management_agent_addr = management_agent_addr;
		scsi_id->sbp2_command_set_spec_id = command_set_spec_id;
		scsi_id->sbp2_command_set = command_set;
		scsi_id->sbp2_unit_characteristics = unit_characteristics;
		scsi_id->sbp2_firmware_revision = firmware_revision;
		scsi_id->workarounds = workarounds;
		if (ud->flags & UNIT_DIRECTORY_HAS_LUN)
			scsi_id->sbp2_device_type_and_lun = ud->lun;
	}
}

/*
 * 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.
 */
static int sbp2_max_speed_and_size(struct scsi_id_instance_data *scsi_id)
{
	struct sbp2scsi_host_info *hi = scsi_id->hi;

	SBP2_DEBUG("sbp2_max_speed_and_size");

	/* Initial setting comes from the hosts speed map */
	scsi_id->speed_code = hi->host->speed_map[NODEID_TO_NODE(hi->host->node_id) * 64
						  + NODEID_TO_NODE(scsi_id->ne->nodeid)];

	/* Bump down our speed if the user requested it */
	if (scsi_id->speed_code > max_speed) {
		scsi_id->speed_code = max_speed;
		SBP2_ERR("Forcing SBP-2 max speed down to %s",
			 hpsb_speedto_str[scsi_id->speed_code]);
	}

	/* Payload size is the lesser of what our speed supports and what
	 * our host supports.  */
	scsi_id->max_payload_size = min(sbp2_speedto_max_payload[scsi_id->speed_code],
					(u8)(hi->host->csr.max_rec - 1));

	HPSB_DEBUG("Node " NODE_BUS_FMT ": Max speed [%s] - Max payload [%u]",
		   NODE_BUS_ARGS(hi->host, scsi_id->ne->nodeid),
		   hpsb_speedto_str[scsi_id->speed_code],
		   1 << ((u32)scsi_id->max_payload_size + 2));

	return(0);
}

/*
 * This function is called in order to perform a SBP-2 agent reset.
 */
static int sbp2_agent_reset(struct scsi_id_instance_data *scsi_id, int wait)
{
	quadlet_t data;
	u64 addr;
	int retval;

	SBP2_DEBUG("sbp2_agent_reset");

	/*
	 * Ok, let's write to the target's management agent register
	 */
	data = ntohl(SBP2_AGENT_RESET_DATA);
	addr = scsi_id->sbp2_command_block_agent_addr + SBP2_AGENT_RESET_OFFSET;

	if (wait)
		retval = hpsb_node_write(scsi_id->ne, addr, &data, 4);
	else
		retval = sbp2util_node_write_no_wait(scsi_id->ne, addr, &data, 4);

	if (retval < 0) {
		SBP2_ERR("hpsb_node_write failed.\n");
		return -EIO;
	}

	/*
	 * Need to make sure orb pointer is written on next command
	 */
	scsi_id->last_orb = NULL;

	return(0);
}

/*
 * This function is called to create the actual command orb and s/g list
 * out of the scsi command itself.
 */
static int sbp2_create_command_orb(struct scsi_id_instance_data *scsi_id,
				   struct sbp2_command_info *command,
				   unchar *scsi_cmd,
				   unsigned int scsi_use_sg,
				   unsigned int scsi_request_bufflen,
				   void *scsi_request_buffer,
				   enum dma_data_direction dma_dir)

{
	struct sbp2scsi_host_info *hi = scsi_id->hi;
	struct scatterlist *sgpnt = (struct scatterlist *) scsi_request_buffer;
	struct sbp2_command_orb *command_orb = &command->command_orb;
	struct sbp2_unrestricted_page_table *scatter_gather_element =
		&command->scatter_gather_element[0];
	u32 sg_count, sg_len, orb_direction;
	dma_addr_t sg_addr;
	int i;

	/*
	 * Set-up our command ORB..
	 *
	 * 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).
	 */
	command_orb->next_ORB_hi = ORB_SET_NULL_PTR(1);
	command_orb->next_ORB_lo = 0x0;
	command_orb->misc = ORB_SET_MAX_PAYLOAD(scsi_id->max_payload_size);
	command_orb->misc |= ORB_SET_SPEED(scsi_id->speed_code);
	command_orb->misc |= ORB_SET_NOTIFY(1);		/* Notify us when complete */

	/*
	 * Get the direction of the transfer. If the direction is unknown, then use our
	 * goofy table as a back-up.
	 */
	switch (dma_dir) {
		case DMA_NONE:
			orb_direction = ORB_DIRECTION_NO_DATA_TRANSFER;
			break;
		case DMA_TO_DEVICE:
			orb_direction = ORB_DIRECTION_WRITE_TO_MEDIA;
			break;
		case DMA_FROM_DEVICE:
			orb_direction = ORB_DIRECTION_READ_FROM_MEDIA;
			break;
		case DMA_BIDIRECTIONAL:
		default:
			SBP2_ERR("SCSI data transfer direction not specified. "
				 "Update the SBP2 direction table in sbp2.h if "
				 "necessary for your application");
			__scsi_print_command(scsi_cmd);
			orb_direction = sbp2scsi_direction_table[*scsi_cmd];
			break;
	}

	/*
	 * Set-up our pagetable stuff... unfortunately, this has become
	 * messier than I'd like. Need to clean this up a bit.   ;-)
	 */
	if (orb_direction == ORB_DIRECTION_NO_DATA_TRANSFER) {

		SBP2_DEBUG("No data transfer");

		/*
		 * Handle no data transfer
		 */
		command_orb->data_descriptor_hi = 0x0;
		command_orb->data_descriptor_lo = 0x0;
		command_orb->misc |= ORB_SET_DIRECTION(1);

	} else if (scsi_use_sg) {

		SBP2_DEBUG("Use scatter/gather");

		/*
		 * Special case if only one element (and less than 64KB in size)
		 */
		if ((scsi_use_sg == 1) && (sgpnt[0].length <= SBP2_MAX_SG_ELEMENT_LENGTH)) {

			SBP2_DEBUG("Only one s/g element");
			command->dma_dir = dma_dir;
			command->dma_size = sgpnt[0].length;
			command->dma_type = CMD_DMA_PAGE;
			command->cmd_dma = pci_map_page(hi->host->pdev,
							sgpnt[0].page,
							sgpnt[0].offset,
							command->dma_size,
							command->dma_dir);
			SBP2_DMA_ALLOC("single page scatter element");

			command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
			command_orb->data_descriptor_lo = command->cmd_dma;
			command_orb->misc |= ORB_SET_DATA_SIZE(command->dma_size);
			command_orb->misc |= ORB_SET_DIRECTION(orb_direction);

		} else {
			int count = pci_map_sg(hi->host->pdev, sgpnt, scsi_use_sg, dma_dir);
			SBP2_DMA_ALLOC("scatter list");

			command->dma_size = scsi_use_sg;
			command->dma_dir = dma_dir;
			command->sge_buffer = sgpnt;

			/* use page tables (s/g) */
			command_orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1);
			command_orb->misc |= ORB_SET_DIRECTION(orb_direction);
			command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
			command_orb->data_descriptor_lo = command->sge_dma;

			/*
			 * Loop through and fill out our sbp-2 page tables
			 * (and split up anything too large)
			 */
			for (i = 0, sg_count = 0 ; i < count; i++, sgpnt++) {
				sg_len = sg_dma_len(sgpnt);
				sg_addr = sg_dma_address(sgpnt);
				while (sg_len) {
					scatter_gather_element[sg_count].segment_base_lo = sg_addr;
					if (sg_len > SBP2_MAX_SG_ELEMENT_LENGTH) {
						scatter_gather_element[sg_count].length_segment_base_hi =
							PAGE_TABLE_SET_SEGMENT_LENGTH(SBP2_MAX_SG_ELEMENT_LENGTH);
						sg_addr += SBP2_MAX_SG_ELEMENT_LENGTH;
						sg_len -= SBP2_MAX_SG_ELEMENT_LENGTH;
					} else {
						scatter_gather_element[sg_count].length_segment_base_hi =
							PAGE_TABLE_SET_SEGMENT_LENGTH(sg_len);
						sg_len = 0;
					}
					sg_count++;
				}
			}

			/* Number of page table (s/g) elements */
			command_orb->misc |= ORB_SET_DATA_SIZE(sg_count);

			sbp2util_packet_dump(scatter_gather_element,
					     (sizeof(struct sbp2_unrestricted_page_table)) * sg_count,
					     "sbp2 s/g list", command->sge_dma);

			/*
			 * Byte swap page tables if necessary
			 */
			sbp2util_cpu_to_be32_buffer(scatter_gather_element,
						    (sizeof(struct sbp2_unrestricted_page_table)) *
						    sg_count);

		}

	} else {

		SBP2_DEBUG("No scatter/gather");

		command->dma_dir = dma_dir;
		command->dma_size = scsi_request_bufflen;
		command->dma_type = CMD_DMA_SINGLE;
		command->cmd_dma = pci_map_single (hi->host->pdev, scsi_request_buffer,
						   command->dma_size,
						   command->dma_dir);
		SBP2_DMA_ALLOC("single bulk");

		/*
		 * Handle case where we get a command w/o s/g enabled (but
		 * check for transfers larger than 64K)
		 */
		if (scsi_request_bufflen <= SBP2_MAX_SG_ELEMENT_LENGTH) {

			command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
			command_orb->data_descriptor_lo = command->cmd_dma;
			command_orb->misc |= ORB_SET_DATA_SIZE(scsi_request_bufflen);
			command_orb->misc |= ORB_SET_DIRECTION(orb_direction);

			/*
			 * Sanity, in case our direction table is not
			 * up-to-date
			 */
			if (!scsi_request_bufflen) {
				command_orb->data_descriptor_hi = 0x0;
				command_orb->data_descriptor_lo = 0x0;
				command_orb->misc |= ORB_SET_DIRECTION(1);
			}

		} else {
			/*
			 * Need to turn this into page tables, since the
			 * buffer is too large.
			 */
			command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
			command_orb->data_descriptor_lo = command->sge_dma;

			/* Use page tables (s/g) */
			command_orb->misc |= ORB_SET_PAGE_TABLE_PRESENT(0x1);
			command_orb->misc |= ORB_SET_DIRECTION(orb_direction);

			/*
			 * fill out our sbp-2 page tables (and split up
			 * the large buffer)
			 */
			sg_count = 0;
			sg_len = scsi_request_bufflen;
			sg_addr = command->cmd_dma;
			while (sg_len) {
				scatter_gather_element[sg_count].segment_base_lo = sg_addr;
				if (sg_len > SBP2_MAX_SG_ELEMENT_LENGTH) {
					scatter_gather_element[sg_count].length_segment_base_hi =
						PAGE_TABLE_SET_SEGMENT_LENGTH(SBP2_MAX_SG_ELEMENT_LENGTH);
					sg_addr += SBP2_MAX_SG_ELEMENT_LENGTH;
					sg_len -= SBP2_MAX_SG_ELEMENT_LENGTH;
				} else {
					scatter_gather_element[sg_count].length_segment_base_hi =
						PAGE_TABLE_SET_SEGMENT_LENGTH(sg_len);
					sg_len = 0;
				}
				sg_count++;
			}

			/* Number of page table (s/g) elements */
			command_orb->misc |= ORB_SET_DATA_SIZE(sg_count);

			sbp2util_packet_dump(scatter_gather_element,
					     (sizeof(struct sbp2_unrestricted_page_table)) * sg_count,
					     "sbp2 s/g list", command->sge_dma);

			/*
			 * Byte swap page tables if necessary
			 */
			sbp2util_cpu_to_be32_buffer(scatter_gather_element,
						    (sizeof(struct sbp2_unrestricted_page_table)) *
						     sg_count);

		}

	}

	/*
	 * Byte swap command ORB if necessary
	 */
	sbp2util_cpu_to_be32_buffer(command_orb, sizeof(struct sbp2_command_orb));

	/*
	 * Put our scsi command in the command ORB
	 */
	memset(command_orb->cdb, 0, 12);
	memcpy(command_orb->cdb, scsi_cmd, COMMAND_SIZE(*scsi_cmd));

	return(0);
}

/*
 * This function is called in order to begin a regular SBP-2 command.
 */
static int sbp2_link_orb_command(struct scsi_id_instance_data *scsi_id,
				 struct sbp2_command_info *command)
{
	struct sbp2scsi_host_info *hi = scsi_id->hi;
	struct sbp2_command_orb *command_orb = &command->command_orb;
	struct node_entry *ne = scsi_id->ne;
	u64 addr;

	outstanding_orb_incr;
	SBP2_ORB_DEBUG("sending command orb %p, total orbs = %x",
			command_orb, global_outstanding_command_orbs);

	pci_dma_sync_single_for_device(hi->host->pdev, command->command_orb_dma,
				       sizeof(struct sbp2_command_orb),
				       PCI_DMA_BIDIRECTIONAL);
	pci_dma_sync_single_for_device(hi->host->pdev, command->sge_dma,
				       sizeof(command->scatter_gather_element),
				       PCI_DMA_BIDIRECTIONAL);
	/*
	 * Check to see if there are any previous orbs to use
	 */
	if (scsi_id->last_orb == NULL) {
		quadlet_t data[2];

		/*
		 * Ok, let's write to the target's management agent register
		 */
		addr = scsi_id->sbp2_command_block_agent_addr + SBP2_ORB_POINTER_OFFSET;
		data[0] = ORB_SET_NODE_ID(hi->host->node_id);
		data[1] = command->command_orb_dma;
		sbp2util_cpu_to_be32_buffer(data, 8);

		SBP2_ORB_DEBUG("write command agent, command orb %p", command_orb);

		if (sbp2util_node_write_no_wait(ne, addr, data, 8) < 0) {
			SBP2_ERR("sbp2util_node_write_no_wait failed.\n");
			return -EIO;
		}

		SBP2_ORB_DEBUG("write command agent complete");

		scsi_id->last_orb = command_orb;
		scsi_id->last_orb_dma = command->command_orb_dma;

	} else {
		quadlet_t data;

		/*
		 * We have an orb already sent (maybe or maybe not
		 * processed) that we can append this orb to. So do so,
		 * and ring the doorbell. Have to be very careful
		 * modifying these next orb pointers, as they are accessed
		 * both by the sbp2 device and us.
		 */
		scsi_id->last_orb->next_ORB_lo =
			cpu_to_be32(command->command_orb_dma);
		/* Tells hardware that this pointer is valid */
		scsi_id->last_orb->next_ORB_hi = 0x0;
		pci_dma_sync_single_for_device(hi->host->pdev, scsi_id->last_orb_dma,
					       sizeof(struct sbp2_command_orb),
					       PCI_DMA_BIDIRECTIONAL);

		/*
		 * Ring the doorbell
		 */
		data = cpu_to_be32(command->command_orb_dma);
		addr = scsi_id->sbp2_command_block_agent_addr + SBP2_DOORBELL_OFFSET;

		SBP2_ORB_DEBUG("ring doorbell, command orb %p", command_orb);

		if (sbp2util_node_write_no_wait(ne, addr, &data, 4) < 0) {
			SBP2_ERR("sbp2util_node_write_no_wait failed");
			return(-EIO);
		}

		scsi_id->last_orb = command_orb;
		scsi_id->last_orb_dma = command->command_orb_dma;

	}
       	return(0);
}

/*
 * This function is called in order to begin a regular SBP-2 command.
 */
static int sbp2_send_command(struct scsi_id_instance_data *scsi_id,
			     struct scsi_cmnd *SCpnt,
			     void (*done)(struct scsi_cmnd *))
{
	unchar *cmd = (unchar *) SCpnt->cmnd;
	unsigned int request_bufflen = SCpnt->request_bufflen;
	struct sbp2_command_info *command;

	SBP2_DEBUG("sbp2_send_command");
#if (CONFIG_IEEE1394_SBP2_DEBUG >= 2) || defined(CONFIG_IEEE1394_SBP2_PACKET_DUMP)
	printk("[scsi command]\n   ");
	scsi_print_command(SCpnt);
#endif
	SBP2_DEBUG("SCSI transfer size = %x", request_bufflen);
	SBP2_DEBUG("SCSI s/g elements = %x", (unsigned int)SCpnt->use_sg);

	/*
	 * Allocate a command orb and s/g structure
	 */
	command = sbp2util_allocate_command_orb(scsi_id, SCpnt, done);
	if (!command) {
		return(-EIO);
	}

	/*
	 * The scsi stack sends down a request_bufflen which does not match the
	 * length field in the scsi cdb. This causes some sbp2 devices to
	 * reject this inquiry command. Fix the request_bufflen.
	 */
	if (*cmd == INQUIRY) {
		if (force_inquiry_hack || scsi_id->workarounds & SBP2_BREAKAGE_INQUIRY_HACK)
			request_bufflen = cmd[4] = 0x24;
		else
			request_bufflen = cmd[4];
	}

	/*
	 * Now actually fill in the comamnd orb and sbp2 s/g list
	 */
	sbp2_create_command_orb(scsi_id, command, cmd, SCpnt->use_sg,
				request_bufflen, SCpnt->request_buffer,
				SCpnt->sc_data_direction);
	/*
	 * Update our cdb if necessary (to handle sbp2 RBC command set
	 * differences). This is where the command set hacks go!   =)
	 */
	sbp2_check_sbp2_command(scsi_id, command->command_orb.cdb);

	sbp2util_packet_dump(&command->command_orb, sizeof(struct sbp2_command_orb),
			     "sbp2 command orb", command->command_orb_dma);

	/*
	 * Initialize status fifo
	 */
	memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block));

	/*
	 * Link up the orb, and ring the doorbell if needed
	 */
	sbp2_link_orb_command(scsi_id, command);

	return(0);
}


/*
 * This function deals with command set differences between Linux scsi
 * command set and sbp2 RBC command set.
 */
static void sbp2_check_sbp2_command(struct scsi_id_instance_data *scsi_id, unchar *cmd)
{
	unchar new_cmd[16];
	u8 device_type = SBP2_DEVICE_TYPE (scsi_id->sbp2_device_type_and_lun);

	SBP2_DEBUG("sbp2_check_sbp2_command");

	switch (*cmd) {

		case READ_6:

			if (sbp2_command_conversion_device_type(device_type)) {

				SBP2_DEBUG("Convert READ_6 to READ_10");

				/*
				 * Need to turn read_6 into read_10
				 */
				new_cmd[0] = 0x28;
				new_cmd[1] = (cmd[1] & 0xe0);
				new_cmd[2] = 0x0;
				new_cmd[3] = (cmd[1] & 0x1f);
				new_cmd[4] = cmd[2];
				new_cmd[5] = cmd[3];
				new_cmd[6] = 0x0;
				new_cmd[7] = 0x0;
				new_cmd[8] = cmd[4];
				new_cmd[9] = cmd[5];

				memcpy(cmd, new_cmd, 10);

			}

			break;

		case WRITE_6:

			if (sbp2_command_conversion_device_type(device_type)) {

				SBP2_DEBUG("Convert WRITE_6 to WRITE_10");

				/*
				 * Need to turn write_6 into write_10
				 */
				new_cmd[0] = 0x2a;
				new_cmd[1] = (cmd[1] & 0xe0);
				new_cmd[2] = 0x0;
				new_cmd[3] = (cmd[1] & 0x1f);
				new_cmd[4] = cmd[2];
				new_cmd[5] = cmd[3];
				new_cmd[6] = 0x0;
				new_cmd[7] = 0x0;
				new_cmd[8] = cmd[4];
				new_cmd[9] = cmd[5];

				memcpy(cmd, new_cmd, 10);

			}

			break;

		case MODE_SENSE:

			if (sbp2_command_conversion_device_type(device_type)) {

				SBP2_DEBUG("Convert MODE_SENSE_6 to MODE_SENSE_10");

				/*
				 * Need to turn mode_sense_6 into mode_sense_10
				 */
				new_cmd[0] = 0x5a;
				new_cmd[1] = cmd[1];
				new_cmd[2] = cmd[2];
				new_cmd[3] = 0x0;
				new_cmd[4] = 0x0;
				new_cmd[5] = 0x0;
				new_cmd[6] = 0x0;
				new_cmd[7] = 0x0;
				new_cmd[8] = cmd[4];
				new_cmd[9] = cmd[5];

				memcpy(cmd, new_cmd, 10);

			}

			break;

		case MODE_SELECT:

			/*
			 * TODO. Probably need to change mode select to 10 byte version
			 */

		default:
			break;
	}

	return;
}

/*
 * Translates SBP-2 status into SCSI sense data for check conditions
 */
static unsigned int sbp2_status_to_sense_data(unchar *sbp2_status, unchar *sense_data)
{
	SBP2_DEBUG("sbp2_status_to_sense_data");

	/*
	 * Ok, it's pretty ugly...   ;-)
	 */
	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];

	return(sbp2_status[8] & 0x3f);	/* return scsi status */
}

/*
 * This function is called after a command is completed, in order to do any necessary SBP-2
 * response data translations for the SCSI stack
 */
static void sbp2_check_sbp2_response(struct scsi_id_instance_data *scsi_id, 
				     struct scsi_cmnd *SCpnt)
{
	u8 *scsi_buf = SCpnt->request_buffer;
	u8 device_type = SBP2_DEVICE_TYPE (scsi_id->sbp2_device_type_and_lun);

	SBP2_DEBUG("sbp2_check_sbp2_response");

	switch (SCpnt->cmnd[0]) {

		case INQUIRY:

			/*
			 * If scsi_id->sbp2_device_type_and_lun is uninitialized, then fill 
			 * this information in from the inquiry response data. Lun is set to zero.
			 */
			if (scsi_id->sbp2_device_type_and_lun == SBP2_DEVICE_TYPE_LUN_UNINITIALIZED) {
				SBP2_DEBUG("Creating sbp2_device_type_and_lun from scsi inquiry data");
				scsi_id->sbp2_device_type_and_lun = (scsi_buf[0] & 0x1f) << 16;
			}

			/*
			 * Make sure data length is ok. Minimum length is 36 bytes
			 */
			if (scsi_buf[4] == 0) {
				scsi_buf[4] = 36 - 5;
			}

			/*
			 * Check for Simple Direct Access Device and change it to TYPE_DISK
			 */
			if ((scsi_buf[0] & 0x1f) == TYPE_RBC) {
				SBP2_DEBUG("Changing TYPE_RBC to TYPE_DISK");
				scsi_buf[0] &= 0xe0;
			}

			/*
			 * Fix ansi revision and response data format
			 */
			scsi_buf[2] |= 2;
			scsi_buf[3] = (scsi_buf[3] & 0xf0) | 2;

			break;

		case MODE_SENSE:

			if (sbp2_command_conversion_device_type(device_type)) {

				SBP2_DEBUG("Modify mode sense response (10 byte version)");

				scsi_buf[0] = scsi_buf[1];	/* Mode data length */
				scsi_buf[1] = scsi_buf[2];	/* Medium type */
				scsi_buf[2] = scsi_buf[3];	/* Device specific parameter */
				scsi_buf[3] = scsi_buf[7];	/* Block descriptor length */
				memcpy(scsi_buf + 4, scsi_buf + 8, scsi_buf[0]);
			}

			break;

		case MODE_SELECT:

			/*
			 * TODO. Probably need to change mode select to 10 byte version
			 */

		default:
			break;
	}
	return;
}

/*
 * This function deals with status writes from the SBP-2 device
 */
static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int destid,
				    quadlet_t *data, u64 addr, size_t length, u16 fl)
{
	struct sbp2scsi_host_info *hi;
	struct scsi_id_instance_data *scsi_id = NULL, *scsi_id_tmp;
	u32 id;
	struct scsi_cmnd *SCpnt = NULL;
	u32 scsi_status = SBP2_SCSI_STATUS_GOOD;
	struct sbp2_command_info *command;

	SBP2_DEBUG("sbp2_handle_status_write");

	sbp2util_packet_dump(data, length, "sbp2 status write by device", (u32)addr);

	if (!host) {
		SBP2_ERR("host is NULL - this is bad!");
		return(RCODE_ADDRESS_ERROR);
	}

	hi = hpsb_get_hostinfo(&sbp2_highlevel, host);

	if (!hi) {
		SBP2_ERR("host info is NULL - this is bad!");
		return(RCODE_ADDRESS_ERROR);
	}

	/*
	 * Find our scsi_id structure by looking at the status fifo address written to by
	 * the sbp2 device.
	 */
	id = SBP2_STATUS_FIFO_OFFSET_TO_ENTRY((u32)(addr - SBP2_STATUS_FIFO_ADDRESS));
	list_for_each_entry(scsi_id_tmp, &hi->scsi_ids, scsi_list) {
		if (scsi_id_tmp->ne->nodeid == nodeid && scsi_id_tmp->ud->id == id) {
			scsi_id = scsi_id_tmp;
			break;
		}
	}

	if (!scsi_id) {
		SBP2_ERR("scsi_id is NULL - device is gone?");
		return(RCODE_ADDRESS_ERROR);
	}

	/*
	 * Put response into scsi_id status fifo...
	 */
	memcpy(&scsi_id->status_block, data, length);

	/*
	 * Byte swap first two quadlets (8 bytes) of status for processing
	 */
	sbp2util_be32_to_cpu_buffer(&scsi_id->status_block, 8);

	/*
	 * Handle command ORB status here if necessary. First, need to match status with command.
	 */
	command = sbp2util_find_command_for_orb(scsi_id, scsi_id->status_block.ORB_offset_lo);
	if (command) {

		SBP2_DEBUG("Found status for command ORB");
		pci_dma_sync_single_for_cpu(hi->host->pdev, command->command_orb_dma,
					    sizeof(struct sbp2_command_orb),
					    PCI_DMA_BIDIRECTIONAL);
		pci_dma_sync_single_for_cpu(hi->host->pdev, command->sge_dma,
					    sizeof(command->scatter_gather_element),
					    PCI_DMA_BIDIRECTIONAL);

		SBP2_ORB_DEBUG("matched command orb %p", &command->command_orb);
		outstanding_orb_decr;

		/*
		 * Matched status with command, now grab scsi command pointers and check status
		 */
		SCpnt = command->Current_SCpnt;
		sbp2util_mark_command_completed(scsi_id, command);

		if (SCpnt) {

			/*
			 * See if the target stored any scsi status information
			 */
			if (STATUS_GET_LENGTH(scsi_id->status_block.ORB_offset_hi_misc) > 1) {
				/*
				 * Translate SBP-2 status to SCSI sense data
				 */
				SBP2_DEBUG("CHECK CONDITION");
				scsi_status = sbp2_status_to_sense_data((unchar *)&scsi_id->status_block, SCpnt->sense_buffer);
			}

			/*
			 * Check to see if the dead bit is set. If so, we'll have to initiate
			 * a fetch agent reset.
			 */
			if (STATUS_GET_DEAD_BIT(scsi_id->status_block.ORB_offset_hi_misc)) {

				/*
				 * Initiate a fetch agent reset.
				 */
				SBP2_DEBUG("Dead bit set - initiating fetch agent reset");
                                sbp2_agent_reset(scsi_id, 0);
			}

			SBP2_ORB_DEBUG("completing command orb %p", &command->command_orb);
		}

		/*
		 * Check here to see if there are no commands in-use. If there are none, we can
		 * null out last orb so that next time around we write directly to the orb pointer...
		 * Quick start saves one 1394 bus transaction.
		 */
		if (list_empty(&scsi_id->sbp2_command_orb_inuse)) {
			scsi_id->last_orb = NULL;
		}

	} else {

		/*
		 * It's probably a login/logout/reconnect status.
		 */
		if ((scsi_id->login_orb_dma == scsi_id->status_block.ORB_offset_lo) ||
		    (scsi_id->query_logins_orb_dma == scsi_id->status_block.ORB_offset_lo) ||
		    (scsi_id->reconnect_orb_dma == scsi_id->status_block.ORB_offset_lo) ||
		    (scsi_id->logout_orb_dma == scsi_id->status_block.ORB_offset_lo)) {
			atomic_set(&scsi_id->sbp2_login_complete, 1);
		}
	}

	if (SCpnt) {

		/* Complete the SCSI command. */
		SBP2_DEBUG("Completing SCSI command");
		sbp2scsi_complete_command(scsi_id, scsi_status, SCpnt,
					  command->Current_done);
		SBP2_ORB_DEBUG("command orb completed");
	}

	return(RCODE_COMPLETE);
}


/**************************************
 * SCSI interface related section
 **************************************/

/*
 * This routine is the main request entry routine for doing I/O. It is
 * called from the scsi stack directly.
 */
static int sbp2scsi_queuecommand(struct scsi_cmnd *SCpnt,
				 void (*done)(struct scsi_cmnd *))
{
	struct scsi_id_instance_data *scsi_id =
		(struct scsi_id_instance_data *)SCpnt->device->host->hostdata[0];
	struct sbp2scsi_host_info *hi;
	int result = DID_NO_CONNECT << 16;

	SBP2_DEBUG("sbp2scsi_queuecommand");

	if (!sbp2util_node_is_available(scsi_id))
		goto done;

	hi = scsi_id->hi;

	if (!hi) {
		SBP2_ERR("sbp2scsi_host_info is NULL - this is bad!");
		goto done;
	}

	/*
	 * Until we handle multiple luns, just return selection time-out
	 * to any IO directed at non-zero LUNs
	 */
	if (SCpnt->device->lun)
		goto done;

	/*
	 * Check for request sense command, and handle it here
	 * (autorequest sense)
	 */
	if (SCpnt->cmnd[0] == REQUEST_SENSE) {
		SBP2_DEBUG("REQUEST_SENSE");
		memcpy(SCpnt->request_buffer, SCpnt->sense_buffer, SCpnt->request_bufflen);
		memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
		sbp2scsi_complete_command(scsi_id, SBP2_SCSI_STATUS_GOOD, SCpnt, done);
		return 0;
	}

	/*
	 * Check to see if we are in the middle of a bus reset.
	 */
	if (!hpsb_node_entry_valid(scsi_id->ne)) {
		SBP2_ERR("Bus reset in progress - rejecting command");
		result = DID_BUS_BUSY << 16;
		goto done;
	}

	/*
	 * Try and send our SCSI command
	 */
	if (sbp2_send_command(scsi_id, SCpnt, done)) {
		SBP2_ERR("Error sending SCSI command");
		sbp2scsi_complete_command(scsi_id, SBP2_SCSI_STATUS_SELECTION_TIMEOUT,
					  SCpnt, done);
	}
	return 0;

done:
	SCpnt->result = result;
	done(SCpnt);
	return 0;
}

/*
 * This function is called in order to complete all outstanding SBP-2
 * commands (in case of resets, etc.).
 */
static void sbp2scsi_complete_all_commands(struct scsi_id_instance_data *scsi_id,
					   u32 status)
{
	struct sbp2scsi_host_info *hi = scsi_id->hi;
	struct list_head *lh;
	struct sbp2_command_info *command;

	SBP2_DEBUG("sbp2scsi_complete_all_commands");

	while (!list_empty(&scsi_id->sbp2_command_orb_inuse)) {
		SBP2_DEBUG("Found pending command to complete");
		lh = scsi_id->sbp2_command_orb_inuse.next;
		command = list_entry(lh, struct sbp2_command_info, list);
		pci_dma_sync_single_for_cpu(hi->host->pdev, command->command_orb_dma,
					    sizeof(struct sbp2_command_orb),
					    PCI_DMA_BIDIRECTIONAL);
		pci_dma_sync_single_for_cpu(hi->host->pdev, command->sge_dma,
					    sizeof(command->scatter_gather_element),
					    PCI_DMA_BIDIRECTIONAL);
		sbp2util_mark_command_completed(scsi_id, command);
		if (command->Current_SCpnt) {
			command->Current_SCpnt->result = status << 16;
			command->Current_done(command->Current_SCpnt);
		}
	}

	return;
}

/*
 * This function is called in order to complete a regular SBP-2 command.
 *
 * This can be called in interrupt context.
 */
static void sbp2scsi_complete_command(struct scsi_id_instance_data *scsi_id,
				      u32 scsi_status, struct scsi_cmnd *SCpnt,
				      void (*done)(struct scsi_cmnd *))
{
	SBP2_DEBUG("sbp2scsi_complete_command");

	/*
	 * Sanity
	 */
	if (!SCpnt) {
		SBP2_ERR("SCpnt is NULL");
		return;
	}

	/*
	 * If a bus reset is in progress and there was an error, don't
	 * complete the command, just let it get retried at the end of the
	 * bus reset.
	 */
	if (!hpsb_node_entry_valid(scsi_id->ne) && (scsi_status != SBP2_SCSI_STATUS_GOOD)) {
		SBP2_ERR("Bus reset in progress - retry command later");
		return;
	}
 
	/*
	 * Switch on scsi status
	 */
	switch (scsi_status) {
		case SBP2_SCSI_STATUS_GOOD:
			SCpnt->result = DID_OK;
			break;

		case SBP2_SCSI_STATUS_BUSY:
			SBP2_ERR("SBP2_SCSI_STATUS_BUSY");
			SCpnt->result = DID_BUS_BUSY << 16;
			break;

		case SBP2_SCSI_STATUS_CHECK_CONDITION:
			SBP2_DEBUG("SBP2_SCSI_STATUS_CHECK_CONDITION");
			SCpnt->result = CHECK_CONDITION << 1;

			/*
			 * Debug stuff
			 */
#if CONFIG_IEEE1394_SBP2_DEBUG >= 1
			scsi_print_command(SCpnt);
			scsi_print_sense("bh", SCpnt);
#endif

			break;

		case SBP2_SCSI_STATUS_SELECTION_TIMEOUT:
			SBP2_ERR("SBP2_SCSI_STATUS_SELECTION_TIMEOUT");
			SCpnt->result = DID_NO_CONNECT << 16;
			scsi_print_command(SCpnt);
			break;

		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;

		default:
			SBP2_ERR("Unsupported SCSI status = %x", scsi_status);
			SCpnt->result = DID_ERROR << 16;
	}

	/*
	 * Take care of any sbp2 response data mucking here (RBC stuff, etc.)
	 */
	if (SCpnt->result == DID_OK) {
		sbp2_check_sbp2_response(scsi_id, SCpnt);
	}

	/*
	 * If a bus reset is in progress and there was an error, complete
	 * the command as busy so that it will get retried.
	 */
	if (!hpsb_node_entry_valid(scsi_id->ne) && (scsi_status != SBP2_SCSI_STATUS_GOOD)) {
		SBP2_ERR("Completing command with busy (bus reset)");
		SCpnt->result = DID_BUS_BUSY << 16;
	}

	/*
	 * If a unit attention occurs, return busy status so it gets
	 * retried... it could have happened because of a 1394 bus reset
	 * or hot-plug...
	 */
#if 0
	if ((scsi_status == SBP2_SCSI_STATUS_CHECK_CONDITION) &&
	    (SCpnt->sense_buffer[2] == UNIT_ATTENTION)) {
		SBP2_DEBUG("UNIT ATTENTION - return busy");
		SCpnt->result = DID_BUS_BUSY << 16;
	}
#endif

	/*
	 * Tell scsi stack that we're done with this command
	 */
	done (SCpnt);
}


static int sbp2scsi_slave_alloc(struct scsi_device *sdev)
{
	((struct scsi_id_instance_data *)sdev->host->hostdata[0])->sdev = sdev;
	return 0;
}


static int sbp2scsi_slave_configure(struct scsi_device *sdev)
{
	blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
	return 0;
}


static void sbp2scsi_slave_destroy(struct scsi_device *sdev)
{
	((struct scsi_id_instance_data *)sdev->host->hostdata[0])->sdev = NULL;
	return;
}


/*
 * Called by scsi stack when something has really gone wrong.  Usually
 * called when a command has timed-out for some reason.
 */
static int sbp2scsi_abort(struct scsi_cmnd *SCpnt)
{
	struct scsi_id_instance_data *scsi_id =
		(struct scsi_id_instance_data *)SCpnt->device->host->hostdata[0];
	struct sbp2scsi_host_info *hi = scsi_id->hi;
	struct sbp2_command_info *command;

	SBP2_ERR("aborting sbp2 command");
	scsi_print_command(SCpnt);

	if (sbp2util_node_is_available(scsi_id)) {

		/*
		 * Right now, just return any matching command structures
		 * to the free pool.
		 */
		command = sbp2util_find_command_for_SCpnt(scsi_id, SCpnt);
		if (command) {
			SBP2_DEBUG("Found command to abort");
			pci_dma_sync_single_for_cpu(hi->host->pdev,
						    command->command_orb_dma,
						    sizeof(struct sbp2_command_orb),
						    PCI_DMA_BIDIRECTIONAL);
			pci_dma_sync_single_for_cpu(hi->host->pdev,
						    command->sge_dma,
						    sizeof(command->scatter_gather_element),
						    PCI_DMA_BIDIRECTIONAL);
			sbp2util_mark_command_completed(scsi_id, command);
			if (command->Current_SCpnt) {
				command->Current_SCpnt->result = DID_ABORT << 16;
				command->Current_done(command->Current_SCpnt);
			}
		}

		/*
		 * Initiate a fetch agent reset.
		 */
		sbp2_agent_reset(scsi_id, 0);
		sbp2scsi_complete_all_commands(scsi_id, DID_BUS_BUSY);
	}

	return(SUCCESS);
}

/*
 * Called by scsi stack when something has really gone wrong.
 */
static int sbp2scsi_reset(struct scsi_cmnd *SCpnt)
{
	struct scsi_id_instance_data *scsi_id =
		(struct scsi_id_instance_data *)SCpnt->device->host->hostdata[0];
	unsigned long flags;

	SBP2_ERR("reset requested");

	spin_lock_irqsave(SCpnt->device->host->host_lock, flags);

	if (sbp2util_node_is_available(scsi_id)) {
		SBP2_ERR("Generating sbp2 fetch agent reset");
		sbp2_agent_reset(scsi_id, 0);
	}

	spin_unlock_irqrestore(SCpnt->device->host->host_lock, flags);

	return SUCCESS;
}

static const char *sbp2scsi_info (struct Scsi_Host *host)
{
        return "SCSI emulation for IEEE-1394 SBP-2 Devices";
}

static ssize_t sbp2_sysfs_ieee1394_id_show(struct device *dev, struct device_attribute *attr, char *buf)
{
	struct scsi_device *sdev;
	struct scsi_id_instance_data *scsi_id;
	int lun;

	if (!(sdev = to_scsi_device(dev)))
		return 0;

	if (!(scsi_id = (struct scsi_id_instance_data *)sdev->host->hostdata[0]))
		return 0;

	if (scsi_id->sbp2_device_type_and_lun == SBP2_DEVICE_TYPE_LUN_UNINITIALIZED)
		lun = 0;
	else
		lun = ORB_SET_LUN(scsi_id->sbp2_device_type_and_lun);

	return sprintf(buf, "%016Lx:%d:%d\n", (unsigned long long)scsi_id->ne->guid,
		       scsi_id->ud->id, lun);
}
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
};

MODULE_AUTHOR("Ben Collins <bcollins@debian.org>");
MODULE_DESCRIPTION("IEEE-1394 SBP-2 protocol driver");
MODULE_SUPPORTED_DEVICE(SBP2_DEVICE_NAME);
MODULE_LICENSE("GPL");

/* SCSI host template */
static struct scsi_host_template scsi_driver_template = {
	.module =			THIS_MODULE,
	.name =				"SBP-2 IEEE-1394",
	.proc_name =			SBP2_DEVICE_NAME,
	.info =				sbp2scsi_info,
	.queuecommand =			sbp2scsi_queuecommand,
	.eh_abort_handler =		sbp2scsi_abort,
	.eh_device_reset_handler =	sbp2scsi_reset,
	.eh_bus_reset_handler =		sbp2scsi_reset,
	.eh_host_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,
	.emulated =			1,
	.sdev_attrs =			sbp2_sysfs_sdev_attrs,
};

static int sbp2_module_init(void)
{
	int ret;

	SBP2_DEBUG("sbp2_module_init");

	printk(KERN_INFO "sbp2: %s\n", version);

	/* Module load debug option to force one command at a time (serializing I/O) */
	if (serialize_io) {
		SBP2_INFO("Driver forced to serialize I/O (serialize_io=1)");
		SBP2_INFO("Try serialize_io=0 for better performance");
		scsi_driver_template.can_queue = 1;
		scsi_driver_template.cmd_per_lun = 1;
	}

	/* Set max sectors (module load option). Default is 255 sectors. */
	scsi_driver_template.max_sectors = max_sectors;


	/* Register our high level driver with 1394 stack */
	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)
{
	SBP2_DEBUG("sbp2_module_exit");

	hpsb_unregister_protocol(&sbp2_driver);

	hpsb_unregister_highlevel(&sbp2_highlevel);
}

module_init(sbp2_module_init);
module_exit(sbp2_module_exit);