aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ieee1394
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2006-07-23 16:16:00 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2006-09-17 13:29:22 -0400
commit3e98eab46d1a482532c653bdb0c006413654d171 (patch)
treeb7135fa6db9b39b3f351a6030df0131fb0514163 /drivers/ieee1394
parentd4018d7fa63d25f3e1ecf6949fca6b81a182231a (diff)
ieee1394: sbp2: safer initialization of status fifo
Sbp2's copy of the status fifo was cleared when management ORBs or new command ORBs were prepared. The latter had potential for a race condition if the block layer's soft IRQ and the 1394 LLD's interrupt handler ran on different CPUs. It would also yield wrong status if a command was completed with non-zero completion status before other commands that had zero completion status, and no new command was enqueued in the meantime. Now, the status buffer is cleared right before it is written. Thus it ends up in the following simpler and safer access pattern: - sbp2_alloc_device: allocates and implicitly clears once, - sbp2_handle_status_write: clears, writes, and reads, - sbp2_query_logins, sbp2_login_device, sbp2_reconnect_device: read. The latter three do not race with sbp2_handle_status_write because of how the protocol works. As a tiny optimization, the first two quadlets of the status never need to be cleared. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/ieee1394')
-rw-r--r--drivers/ieee1394/sbp2.c80
1 files changed, 30 insertions, 50 deletions
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
index 11595df8b75e..c6776909747a 100644
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -1182,7 +1182,6 @@ static int sbp2_query_logins(struct scsi_id_instance_data *scsi_id)
1182 "sbp2 query logins orb", scsi_id->query_logins_orb_dma); 1182 "sbp2 query logins orb", scsi_id->query_logins_orb_dma);
1183 1183
1184 memset(scsi_id->query_logins_response, 0, sizeof(struct sbp2_query_logins_response)); 1184 memset(scsi_id->query_logins_response, 0, sizeof(struct sbp2_query_logins_response));
1185 memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block));
1186 1185
1187 data[0] = ORB_SET_NODE_ID(hi->host->node_id); 1186 data[0] = ORB_SET_NODE_ID(hi->host->node_id);
1188 data[1] = scsi_id->query_logins_orb_dma; 1187 data[1] = scsi_id->query_logins_orb_dma;
@@ -1278,7 +1277,6 @@ static int sbp2_login_device(struct scsi_id_instance_data *scsi_id)
1278 "sbp2 login orb", scsi_id->login_orb_dma); 1277 "sbp2 login orb", scsi_id->login_orb_dma);
1279 1278
1280 memset(scsi_id->login_response, 0, sizeof(struct sbp2_login_response)); 1279 memset(scsi_id->login_response, 0, sizeof(struct sbp2_login_response));
1281 memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block));
1282 1280
1283 data[0] = ORB_SET_NODE_ID(hi->host->node_id); 1281 data[0] = ORB_SET_NODE_ID(hi->host->node_id);
1284 data[1] = scsi_id->login_orb_dma; 1282 data[1] = scsi_id->login_orb_dma;
@@ -1445,14 +1443,6 @@ static int sbp2_reconnect_device(struct scsi_id_instance_data *scsi_id)
1445 sbp2util_packet_dump(scsi_id->reconnect_orb, sizeof(struct sbp2_reconnect_orb), 1443 sbp2util_packet_dump(scsi_id->reconnect_orb, sizeof(struct sbp2_reconnect_orb),
1446 "sbp2 reconnect orb", scsi_id->reconnect_orb_dma); 1444 "sbp2 reconnect orb", scsi_id->reconnect_orb_dma);
1447 1445
1448 /*
1449 * Initialize status fifo
1450 */
1451 memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block));
1452
1453 /*
1454 * Ok, let's write to the target's management agent register
1455 */
1456 data[0] = ORB_SET_NODE_ID(hi->host->node_id); 1446 data[0] = ORB_SET_NODE_ID(hi->host->node_id);
1457 data[1] = scsi_id->reconnect_orb_dma; 1447 data[1] = scsi_id->reconnect_orb_dma;
1458 sbp2util_cpu_to_be32_buffer(data, 8); 1448 sbp2util_cpu_to_be32_buffer(data, 8);
@@ -2069,11 +2059,6 @@ static int sbp2_send_command(struct scsi_id_instance_data *scsi_id,
2069 "sbp2 command orb", command->command_orb_dma); 2059 "sbp2 command orb", command->command_orb_dma);
2070 2060
2071 /* 2061 /*
2072 * Initialize status fifo
2073 */
2074 memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block));
2075
2076 /*
2077 * Link up the orb, and ring the doorbell if needed 2062 * Link up the orb, and ring the doorbell if needed
2078 */ 2063 */
2079 sbp2_link_orb_command(scsi_id, command); 2064 sbp2_link_orb_command(scsi_id, command);
@@ -2114,12 +2099,14 @@ static unsigned int sbp2_status_to_sense_data(unchar *sbp2_status, unchar *sense
2114/* 2099/*
2115 * This function deals with status writes from the SBP-2 device 2100 * This function deals with status writes from the SBP-2 device
2116 */ 2101 */
2117static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int destid, 2102static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid,
2118 quadlet_t *data, u64 addr, size_t length, u16 fl) 2103 int destid, quadlet_t *data, u64 addr,
2104 size_t length, u16 fl)
2119{ 2105{
2120 struct sbp2scsi_host_info *hi; 2106 struct sbp2scsi_host_info *hi;
2121 struct scsi_id_instance_data *scsi_id = NULL, *scsi_id_tmp; 2107 struct scsi_id_instance_data *scsi_id = NULL, *scsi_id_tmp;
2122 struct scsi_cmnd *SCpnt = NULL; 2108 struct scsi_cmnd *SCpnt = NULL;
2109 struct sbp2_status_block *sb;
2123 u32 scsi_status = SBP2_SCSI_STATUS_GOOD; 2110 u32 scsi_status = SBP2_SCSI_STATUS_GOOD;
2124 struct sbp2_command_info *command; 2111 struct sbp2_command_info *command;
2125 unsigned long flags; 2112 unsigned long flags;
@@ -2158,19 +2145,21 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int dest
2158 } 2145 }
2159 2146
2160 /* 2147 /*
2161 * Put response into scsi_id status fifo... 2148 * Put response into scsi_id status fifo buffer. The first two bytes
2149 * come in big endian bit order. Often the target writes only a
2150 * truncated status block, minimally the first two quadlets. The rest
2151 * is implied to be zeros.
2162 */ 2152 */
2163 memcpy(&scsi_id->status_block, data, length); 2153 sb = &scsi_id->status_block;
2154 memset(sb->command_set_dependent, 0, sizeof(sb->command_set_dependent));
2155 memcpy(sb, data, length);
2156 sbp2util_be32_to_cpu_buffer(sb, 8);
2164 2157
2165 /* 2158 /*
2166 * Byte swap first two quadlets (8 bytes) of status for processing 2159 * Handle command ORB status here if necessary. First, need to match
2160 * status with command.
2167 */ 2161 */
2168 sbp2util_be32_to_cpu_buffer(&scsi_id->status_block, 8); 2162 command = sbp2util_find_command_for_orb(scsi_id, sb->ORB_offset_lo);
2169
2170 /*
2171 * Handle command ORB status here if necessary. First, need to match status with command.
2172 */
2173 command = sbp2util_find_command_for_orb(scsi_id, scsi_id->status_block.ORB_offset_lo);
2174 if (command) { 2163 if (command) {
2175 2164
2176 SBP2_DEBUG("Found status for command ORB"); 2165 SBP2_DEBUG("Found status for command ORB");
@@ -2185,7 +2174,8 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int dest
2185 outstanding_orb_decr; 2174 outstanding_orb_decr;
2186 2175
2187 /* 2176 /*
2188 * Matched status with command, now grab scsi command pointers and check status 2177 * Matched status with command, now grab scsi command pointers
2178 * and check status.
2189 */ 2179 */
2190 SCpnt = command->Current_SCpnt; 2180 SCpnt = command->Current_SCpnt;
2191 spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags); 2181 spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
@@ -2193,28 +2183,22 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int dest
2193 spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags); 2183 spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
2194 2184
2195 if (SCpnt) { 2185 if (SCpnt) {
2196
2197 /* 2186 /*
2198 * See if the target stored any scsi status information 2187 * See if the target stored any scsi status information.
2199 */ 2188 */
2200 if (STATUS_GET_LENGTH(scsi_id->status_block.ORB_offset_hi_misc) > 1) { 2189 if (STATUS_GET_LENGTH(sb->ORB_offset_hi_misc) > 1) {
2201 /*
2202 * Translate SBP-2 status to SCSI sense data
2203 */
2204 SBP2_DEBUG("CHECK CONDITION"); 2190 SBP2_DEBUG("CHECK CONDITION");
2205 scsi_status = sbp2_status_to_sense_data((unchar *)&scsi_id->status_block, SCpnt->sense_buffer); 2191 scsi_status = sbp2_status_to_sense_data(
2192 (unchar *)sb, SCpnt->sense_buffer);
2206 } 2193 }
2207 2194
2208 /* 2195 /*
2209 * Check to see if the dead bit is set. If so, we'll have to initiate 2196 * Check to see if the dead bit is set. If so, we'll
2210 * a fetch agent reset. 2197 * have to initiate a fetch agent reset.
2211 */ 2198 */
2212 if (STATUS_GET_DEAD_BIT(scsi_id->status_block.ORB_offset_hi_misc)) { 2199 if (STATUS_GET_DEAD_BIT(sb->ORB_offset_hi_misc)) {
2213 2200 SBP2_DEBUG("Dead bit set - "
2214 /* 2201 "initiating fetch agent reset");
2215 * Initiate a fetch agent reset.
2216 */
2217 SBP2_DEBUG("Dead bit set - initiating fetch agent reset");
2218 sbp2_agent_reset(scsi_id, 0); 2202 sbp2_agent_reset(scsi_id, 0);
2219 } 2203 }
2220 2204
@@ -2235,21 +2219,17 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int dest
2235 spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags); 2219 spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
2236 2220
2237 } else { 2221 } else {
2238
2239 /* 2222 /*
2240 * It's probably a login/logout/reconnect status. 2223 * It's probably a login/logout/reconnect status.
2241 */ 2224 */
2242 if ((scsi_id->login_orb_dma == scsi_id->status_block.ORB_offset_lo) || 2225 if ((sb->ORB_offset_lo == scsi_id->reconnect_orb_dma) ||
2243 (scsi_id->query_logins_orb_dma == scsi_id->status_block.ORB_offset_lo) || 2226 (sb->ORB_offset_lo == scsi_id->login_orb_dma) ||
2244 (scsi_id->reconnect_orb_dma == scsi_id->status_block.ORB_offset_lo) || 2227 (sb->ORB_offset_lo == scsi_id->query_logins_orb_dma) ||
2245 (scsi_id->logout_orb_dma == scsi_id->status_block.ORB_offset_lo)) { 2228 (sb->ORB_offset_lo == scsi_id->logout_orb_dma))
2246 atomic_set(&scsi_id->sbp2_login_complete, 1); 2229 atomic_set(&scsi_id->sbp2_login_complete, 1);
2247 }
2248 } 2230 }
2249 2231
2250 if (SCpnt) { 2232 if (SCpnt) {
2251
2252 /* Complete the SCSI command. */
2253 SBP2_DEBUG("Completing SCSI command"); 2233 SBP2_DEBUG("Completing SCSI command");
2254 sbp2scsi_complete_command(scsi_id, scsi_status, SCpnt, 2234 sbp2scsi_complete_command(scsi_id, scsi_status, SCpnt,
2255 command->Current_done); 2235 command->Current_done);