aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2006-01-31 00:13:33 -0500
committerJody McIntyre <scjody@modernduck.com>2006-02-23 00:28:52 -0500
commit35bdddb83f62978b5fad82a14fbfd78cc3a5a60c (patch)
treeb5fcfd00b9af8815dd42e3d65e2f9f2e453f4a89
parentbf637ec3ef4159da3dd156ecf6f6987d8c8c5dae (diff)
sbp2: variable status FIFO address (fix login timeout)
Let the ieee1394 core select a suitable 1394 address range for sbp2's status FIFO instead of using a fixed range. Since the core only selects addresses which are guaranteed to be out of the "physical range" as per OHCI 1.1, this patch also fixes an old bug: OHCI controllers which implement a writeable PhysicalUpperBound register included sbp2's status FIFO in the physical range. That way sbp2 was never notified of a succesful login and always failed after timeout. Affected OHCI host adapters include ALi and Fujitsu controllers. As another side effect of this patch, the status FIFO is no longer located in a range for which OHCI chips perform "posted writes". Each status write now requires a response subaction. But since large data transfers involve only few status writes, there is no measurable decrease of I/O throughput. What's more, the status FIFO is now safe from potential host bus errors. Nevertheless, posted writes could be re-enabled by extensions to the ARM features of the 1394 stack. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> Signed-off-by: Jody McIntyre <scjody@modernduck.com> (cherry picked from b2d38cccad4ef80d6b672b8f89aae5fe2907b113 commit)
-rw-r--r--drivers/ieee1394/sbp2.c64
-rw-r--r--drivers/ieee1394/sbp2.h64
2 files changed, 59 insertions, 69 deletions
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
index 8963dd484eb9..0672224fa109 100644
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -748,11 +748,6 @@ static struct scsi_id_instance_data *sbp2_alloc_device(struct unit_directory *ud
748 hi->host = ud->ne->host; 748 hi->host = ud->ne->host;
749 INIT_LIST_HEAD(&hi->scsi_ids); 749 INIT_LIST_HEAD(&hi->scsi_ids);
750 750
751 /* Register our sbp2 status address space... */
752 hpsb_register_addrspace(&sbp2_highlevel, ud->ne->host, &sbp2_ops,
753 SBP2_STATUS_FIFO_ADDRESS,
754 SBP2_STATUS_FIFO_ADDRESS +
755 SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(SBP2_MAX_UDS_PER_NODE+1));
756#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA 751#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
757 /* Handle data movement if physical dma is not 752 /* Handle data movement if physical dma is not
758 * enabled/supportedon host controller */ 753 * enabled/supportedon host controller */
@@ -765,6 +760,18 @@ static struct scsi_id_instance_data *sbp2_alloc_device(struct unit_directory *ud
765 760
766 list_add_tail(&scsi_id->scsi_list, &hi->scsi_ids); 761 list_add_tail(&scsi_id->scsi_list, &hi->scsi_ids);
767 762
763 /* Register the status FIFO address range. We could use the same FIFO
764 * for targets at different nodes. However we need different FIFOs per
765 * target in order to support multi-unit devices. */
766 scsi_id->status_fifo_addr = hpsb_allocate_and_register_addrspace(
767 &sbp2_highlevel, ud->ne->host, &sbp2_ops,
768 sizeof(struct sbp2_status_block), sizeof(quadlet_t),
769 ~0ULL, ~0ULL);
770 if (!scsi_id->status_fifo_addr) {
771 SBP2_ERR("failed to allocate status FIFO address range");
772 goto failed_alloc;
773 }
774
768 /* Register our host with the SCSI stack. */ 775 /* Register our host with the SCSI stack. */
769 scsi_host = scsi_host_alloc(&scsi_driver_template, 776 scsi_host = scsi_host_alloc(&scsi_driver_template,
770 sizeof(unsigned long)); 777 sizeof(unsigned long));
@@ -1003,6 +1010,10 @@ static void sbp2_remove_device(struct scsi_id_instance_data *scsi_id)
1003 SBP2_DMA_FREE("single query logins data"); 1010 SBP2_DMA_FREE("single query logins data");
1004 } 1011 }
1005 1012
1013 if (scsi_id->status_fifo_addr)
1014 hpsb_unregister_addrspace(&sbp2_highlevel, hi->host,
1015 scsi_id->status_fifo_addr);
1016
1006 scsi_id->ud->device.driver_data = NULL; 1017 scsi_id->ud->device.driver_data = NULL;
1007 1018
1008 SBP2_DEBUG("SBP-2 device removed, SCSI ID = %d", scsi_id->ud->id); 1019 SBP2_DEBUG("SBP-2 device removed, SCSI ID = %d", scsi_id->ud->id);
@@ -1081,11 +1092,10 @@ static int sbp2_query_logins(struct scsi_id_instance_data *scsi_id)
1081 ORB_SET_QUERY_LOGINS_RESP_LENGTH(sizeof(struct sbp2_query_logins_response)); 1092 ORB_SET_QUERY_LOGINS_RESP_LENGTH(sizeof(struct sbp2_query_logins_response));
1082 SBP2_DEBUG("sbp2_query_logins: reserved_resp_length initialized"); 1093 SBP2_DEBUG("sbp2_query_logins: reserved_resp_length initialized");
1083 1094
1084 scsi_id->query_logins_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO + 1095 scsi_id->query_logins_orb->status_fifo_hi =
1085 SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(scsi_id->ud->id); 1096 ORB_SET_STATUS_FIFO_HI(scsi_id->status_fifo_addr, hi->host->node_id);
1086 scsi_id->query_logins_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) | 1097 scsi_id->query_logins_orb->status_fifo_lo =
1087 SBP2_STATUS_FIFO_ADDRESS_HI); 1098 ORB_SET_STATUS_FIFO_LO(scsi_id->status_fifo_addr);
1088 SBP2_DEBUG("sbp2_query_logins: status FIFO initialized");
1089 1099
1090 sbp2util_cpu_to_be32_buffer(scsi_id->query_logins_orb, sizeof(struct sbp2_query_logins_orb)); 1100 sbp2util_cpu_to_be32_buffer(scsi_id->query_logins_orb, sizeof(struct sbp2_query_logins_orb));
1091 1101
@@ -1190,11 +1200,10 @@ static int sbp2_login_device(struct scsi_id_instance_data *scsi_id)
1190 ORB_SET_LOGIN_RESP_LENGTH(sizeof(struct sbp2_login_response)); 1200 ORB_SET_LOGIN_RESP_LENGTH(sizeof(struct sbp2_login_response));
1191 SBP2_DEBUG("sbp2_login_device: passwd_resp_lengths initialized"); 1201 SBP2_DEBUG("sbp2_login_device: passwd_resp_lengths initialized");
1192 1202
1193 scsi_id->login_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO + 1203 scsi_id->login_orb->status_fifo_hi =
1194 SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(scsi_id->ud->id); 1204 ORB_SET_STATUS_FIFO_HI(scsi_id->status_fifo_addr, hi->host->node_id);
1195 scsi_id->login_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) | 1205 scsi_id->login_orb->status_fifo_lo =
1196 SBP2_STATUS_FIFO_ADDRESS_HI); 1206 ORB_SET_STATUS_FIFO_LO(scsi_id->status_fifo_addr);
1197 SBP2_DEBUG("sbp2_login_device: status FIFO initialized");
1198 1207
1199 /* 1208 /*
1200 * Byte swap ORB if necessary 1209 * Byte swap ORB if necessary
@@ -1307,10 +1316,10 @@ static int sbp2_logout_device(struct scsi_id_instance_data *scsi_id)
1307 scsi_id->logout_orb->login_ID_misc |= ORB_SET_NOTIFY(1); 1316 scsi_id->logout_orb->login_ID_misc |= ORB_SET_NOTIFY(1);
1308 1317
1309 scsi_id->logout_orb->reserved5 = 0x0; 1318 scsi_id->logout_orb->reserved5 = 0x0;
1310 scsi_id->logout_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO + 1319 scsi_id->logout_orb->status_fifo_hi =
1311 SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(scsi_id->ud->id); 1320 ORB_SET_STATUS_FIFO_HI(scsi_id->status_fifo_addr, hi->host->node_id);
1312 scsi_id->logout_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) | 1321 scsi_id->logout_orb->status_fifo_lo =
1313 SBP2_STATUS_FIFO_ADDRESS_HI); 1322 ORB_SET_STATUS_FIFO_LO(scsi_id->status_fifo_addr);
1314 1323
1315 /* 1324 /*
1316 * Byte swap ORB if necessary 1325 * Byte swap ORB if necessary
@@ -1372,10 +1381,10 @@ static int sbp2_reconnect_device(struct scsi_id_instance_data *scsi_id)
1372 scsi_id->reconnect_orb->login_ID_misc |= ORB_SET_NOTIFY(1); 1381 scsi_id->reconnect_orb->login_ID_misc |= ORB_SET_NOTIFY(1);
1373 1382
1374 scsi_id->reconnect_orb->reserved5 = 0x0; 1383 scsi_id->reconnect_orb->reserved5 = 0x0;
1375 scsi_id->reconnect_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO + 1384 scsi_id->reconnect_orb->status_fifo_hi =
1376 SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(scsi_id->ud->id); 1385 ORB_SET_STATUS_FIFO_HI(scsi_id->status_fifo_addr, hi->host->node_id);
1377 scsi_id->reconnect_orb->status_FIFO_hi = 1386 scsi_id->reconnect_orb->status_fifo_lo =
1378 (ORB_SET_NODE_ID(hi->host->node_id) | SBP2_STATUS_FIFO_ADDRESS_HI); 1387 ORB_SET_STATUS_FIFO_LO(scsi_id->status_fifo_addr);
1379 1388
1380 /* 1389 /*
1381 * Byte swap ORB if necessary 1390 * Byte swap ORB if necessary
@@ -2112,7 +2121,6 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int dest
2112{ 2121{
2113 struct sbp2scsi_host_info *hi; 2122 struct sbp2scsi_host_info *hi;
2114 struct scsi_id_instance_data *scsi_id = NULL, *scsi_id_tmp; 2123 struct scsi_id_instance_data *scsi_id = NULL, *scsi_id_tmp;
2115 u32 id;
2116 struct scsi_cmnd *SCpnt = NULL; 2124 struct scsi_cmnd *SCpnt = NULL;
2117 u32 scsi_status = SBP2_SCSI_STATUS_GOOD; 2125 u32 scsi_status = SBP2_SCSI_STATUS_GOOD;
2118 struct sbp2_command_info *command; 2126 struct sbp2_command_info *command;
@@ -2135,12 +2143,12 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int dest
2135 } 2143 }
2136 2144
2137 /* 2145 /*
2138 * Find our scsi_id structure by looking at the status fifo address written to by 2146 * Find our scsi_id structure by looking at the status fifo address
2139 * the sbp2 device. 2147 * written to by the sbp2 device.
2140 */ 2148 */
2141 id = SBP2_STATUS_FIFO_OFFSET_TO_ENTRY((u32)(addr - SBP2_STATUS_FIFO_ADDRESS));
2142 list_for_each_entry(scsi_id_tmp, &hi->scsi_ids, scsi_list) { 2149 list_for_each_entry(scsi_id_tmp, &hi->scsi_ids, scsi_list) {
2143 if (scsi_id_tmp->ne->nodeid == nodeid && scsi_id_tmp->ud->id == id) { 2150 if (scsi_id_tmp->ne->nodeid == nodeid &&
2151 scsi_id_tmp->status_fifo_addr == addr) {
2144 scsi_id = scsi_id_tmp; 2152 scsi_id = scsi_id_tmp;
2145 break; 2153 break;
2146 } 2154 }
diff --git a/drivers/ieee1394/sbp2.h b/drivers/ieee1394/sbp2.h
index 900ea1d25e71..e2d357a9ea3a 100644
--- a/drivers/ieee1394/sbp2.h
+++ b/drivers/ieee1394/sbp2.h
@@ -33,15 +33,17 @@
33#define ORB_DIRECTION_NO_DATA_TRANSFER 0x2 33#define ORB_DIRECTION_NO_DATA_TRANSFER 0x2
34 34
35#define ORB_SET_NULL_PTR(value) ((value & 0x1) << 31) 35#define ORB_SET_NULL_PTR(value) ((value & 0x1) << 31)
36#define ORB_SET_NOTIFY(value) ((value & 0x1) << 31) 36#define ORB_SET_NOTIFY(value) ((value & 0x1) << 31)
37#define ORB_SET_RQ_FMT(value) ((value & 0x3) << 29) /* unused ? */ 37#define ORB_SET_RQ_FMT(value) ((value & 0x3) << 29) /* unused ? */
38#define ORB_SET_NODE_ID(value) ((value & 0xffff) << 16) 38#define ORB_SET_NODE_ID(value) ((value & 0xffff) << 16)
39#define ORB_SET_DATA_SIZE(value) (value & 0xffff) 39#define ORB_SET_STATUS_FIFO_HI(value, id) (value >> 32 | ORB_SET_NODE_ID(id))
40#define ORB_SET_PAGE_SIZE(value) ((value & 0x7) << 16) 40#define ORB_SET_STATUS_FIFO_LO(value) (value & 0xffffffff)
41#define ORB_SET_PAGE_TABLE_PRESENT(value) ((value & 0x1) << 19) 41#define ORB_SET_DATA_SIZE(value) (value & 0xffff)
42#define ORB_SET_MAX_PAYLOAD(value) ((value & 0xf) << 20) 42#define ORB_SET_PAGE_SIZE(value) ((value & 0x7) << 16)
43#define ORB_SET_SPEED(value) ((value & 0x7) << 24) 43#define ORB_SET_PAGE_TABLE_PRESENT(value) ((value & 0x1) << 19)
44#define ORB_SET_DIRECTION(value) ((value & 0x1) << 27) 44#define ORB_SET_MAX_PAYLOAD(value) ((value & 0xf) << 20)
45#define ORB_SET_SPEED(value) ((value & 0x7) << 24)
46#define ORB_SET_DIRECTION(value) ((value & 0x1) << 27)
45 47
46struct sbp2_command_orb { 48struct sbp2_command_orb {
47 volatile u32 next_ORB_hi; 49 volatile u32 next_ORB_hi;
@@ -76,8 +78,8 @@ struct sbp2_login_orb {
76 u32 login_response_lo; 78 u32 login_response_lo;
77 u32 lun_misc; 79 u32 lun_misc;
78 u32 passwd_resp_lengths; 80 u32 passwd_resp_lengths;
79 u32 status_FIFO_hi; 81 u32 status_fifo_hi;
80 u32 status_FIFO_lo; 82 u32 status_fifo_lo;
81}; 83};
82 84
83#define RESPONSE_GET_LOGIN_ID(value) (value & 0xffff) 85#define RESPONSE_GET_LOGIN_ID(value) (value & 0xffff)
@@ -102,8 +104,8 @@ struct sbp2_query_logins_orb {
102 u32 query_response_lo; 104 u32 query_response_lo;
103 u32 lun_misc; 105 u32 lun_misc;
104 u32 reserved_resp_length; 106 u32 reserved_resp_length;
105 u32 status_FIFO_hi; 107 u32 status_fifo_hi;
106 u32 status_FIFO_lo; 108 u32 status_fifo_lo;
107}; 109};
108 110
109#define RESPONSE_GET_MAX_LOGINS(value) (value & 0xffff) 111#define RESPONSE_GET_MAX_LOGINS(value) (value & 0xffff)
@@ -123,8 +125,8 @@ struct sbp2_reconnect_orb {
123 u32 reserved4; 125 u32 reserved4;
124 u32 login_ID_misc; 126 u32 login_ID_misc;
125 u32 reserved5; 127 u32 reserved5;
126 u32 status_FIFO_hi; 128 u32 status_fifo_hi;
127 u32 status_FIFO_lo; 129 u32 status_fifo_lo;
128}; 130};
129 131
130struct sbp2_logout_orb { 132struct sbp2_logout_orb {
@@ -134,8 +136,8 @@ struct sbp2_logout_orb {
134 u32 reserved4; 136 u32 reserved4;
135 u32 login_ID_misc; 137 u32 login_ID_misc;
136 u32 reserved5; 138 u32 reserved5;
137 u32 status_FIFO_hi; 139 u32 status_fifo_hi;
138 u32 status_FIFO_lo; 140 u32 status_fifo_lo;
139}; 141};
140 142
141#define PAGE_TABLE_SET_SEGMENT_BASE_HI(value) (value & 0xffff) 143#define PAGE_TABLE_SET_SEGMENT_BASE_HI(value) (value & 0xffff)
@@ -195,30 +197,6 @@ struct sbp2_status_block {
195 * Miscellaneous SBP2 related config rom defines 197 * Miscellaneous SBP2 related config rom defines
196 */ 198 */
197 199
198/* The status fifo address definition below is used as a base for each
199 * node, which a chunk seperately assigned to each unit directory in the
200 * node. For example, 0xfffe00000000ULL is used for the first sbp2 device
201 * detected on node 0, 0xfffe00000020ULL for the next sbp2 device on node
202 * 0, and so on.
203 *
204 * Note: We could use a single status fifo address for all sbp2 devices,
205 * and figure out which sbp2 device the status belongs to by looking at
206 * the source node id of the status write... but, using separate addresses
207 * for each sbp2 unit directory allows for better code and the ability to
208 * support multiple luns within a single 1394 node.
209 *
210 * Also note that we choose the address range below as it is a region
211 * specified for write posting, where the ohci controller will
212 * automatically send an ack_complete when the status is written by the
213 * sbp2 device... saving a split transaction. =)
214 */
215#define SBP2_STATUS_FIFO_ADDRESS 0xfffe00000000ULL
216#define SBP2_STATUS_FIFO_ADDRESS_HI 0xfffe
217#define SBP2_STATUS_FIFO_ADDRESS_LO 0x0
218
219#define SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(entry) ((entry) << 5)
220#define SBP2_STATUS_FIFO_OFFSET_TO_ENTRY(offset) ((offset) >> 5)
221
222#define SBP2_UNIT_DIRECTORY_OFFSET_KEY 0xd1 200#define SBP2_UNIT_DIRECTORY_OFFSET_KEY 0xd1
223#define SBP2_CSR_OFFSET_KEY 0x54 201#define SBP2_CSR_OFFSET_KEY 0x54
224#define SBP2_UNIT_SPEC_ID_KEY 0x12 202#define SBP2_UNIT_SPEC_ID_KEY 0x12
@@ -258,7 +236,6 @@ struct sbp2_status_block {
258 */ 236 */
259 237
260#define SBP2_MAX_SG_ELEMENT_LENGTH 0xf000 238#define SBP2_MAX_SG_ELEMENT_LENGTH 0xf000
261#define SBP2_MAX_UDS_PER_NODE 16 /* Maximum scsi devices per node */
262#define SBP2_MAX_SECTORS 255 /* Max sectors supported */ 239#define SBP2_MAX_SECTORS 255 /* Max sectors supported */
263#define SBP2_MAX_CMDS 8 /* This should be safe */ 240#define SBP2_MAX_CMDS 8 /* This should be safe */
264 241
@@ -338,6 +315,11 @@ struct scsi_id_instance_data {
338 u32 sbp2_firmware_revision; 315 u32 sbp2_firmware_revision;
339 316
340 /* 317 /*
318 * Address for the device to write status blocks to
319 */
320 u64 status_fifo_addr;
321
322 /*
341 * Variable used for logins, reconnects, logouts, query logins 323 * Variable used for logins, reconnects, logouts, query logins
342 */ 324 */
343 atomic_t sbp2_login_complete; 325 atomic_t sbp2_login_complete;