diff options
author | Steve Cameron <scameron@quandary.americas.cpqcorp.net> | 2007-10-17 02:27:37 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-17 11:42:55 -0400 |
commit | 1a614f505193fcfc1b298643268a5db5b48e297f (patch) | |
tree | 80413131fca8758fe31e0fb4d383f80f5e75834f | |
parent | 7fdfd4065c264bddd2d9277470a6a99d34e01bef (diff) |
cciss: fix error reporting for SG_IO
This fixes a problem with the way cciss was filling out the "errors" field
of the request structure upon completion of requests. Previously, it just
put a 1 or a 0 in there and used the negation of this as the uptodate
parameter to one of the functions in the block layer, being a block device.
For the SG_IO ioctl, this was not sufficient, and we noticed that, for
example, sg_turs from sg3_utils did not correctly detect problems due to
cciss having set rq->errors incorrectly.
Signed-off-by: Stephen M. Cameron <steve.cameron@hp.com>
Acked-by: Mike Miller <mike.miller@hp.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/block/cciss.c | 79 |
1 files changed, 61 insertions, 18 deletions
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 3fb7e8bc436d..5c269c00d6eb 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c | |||
@@ -2365,30 +2365,55 @@ static inline void resend_cciss_cmd(ctlr_info_t *h, CommandList_struct *c) | |||
2365 | start_io(h); | 2365 | start_io(h); |
2366 | } | 2366 | } |
2367 | 2367 | ||
2368 | static inline unsigned int make_status_bytes(unsigned int scsi_status_byte, | ||
2369 | unsigned int msg_byte, unsigned int host_byte, | ||
2370 | unsigned int driver_byte) | ||
2371 | { | ||
2372 | /* inverse of macros in scsi.h */ | ||
2373 | return (scsi_status_byte & 0xff) | | ||
2374 | ((msg_byte & 0xff) << 8) | | ||
2375 | ((host_byte & 0xff) << 16) | | ||
2376 | ((driver_byte & 0xff) << 24); | ||
2377 | } | ||
2378 | |||
2368 | static inline int evaluate_target_status(CommandList_struct *cmd) | 2379 | static inline int evaluate_target_status(CommandList_struct *cmd) |
2369 | { | 2380 | { |
2370 | unsigned char sense_key; | 2381 | unsigned char sense_key; |
2371 | int error_count = 1; | 2382 | unsigned char status_byte, msg_byte, host_byte, driver_byte; |
2383 | int error_value; | ||
2384 | |||
2385 | /* If we get in here, it means we got "target status", that is, scsi status */ | ||
2386 | status_byte = cmd->err_info->ScsiStatus; | ||
2387 | driver_byte = DRIVER_OK; | ||
2388 | msg_byte = cmd->err_info->CommandStatus; /* correct? seems too device specific */ | ||
2389 | |||
2390 | if (blk_pc_request(cmd->rq)) | ||
2391 | host_byte = DID_PASSTHROUGH; | ||
2392 | else | ||
2393 | host_byte = DID_OK; | ||
2394 | |||
2395 | error_value = make_status_bytes(status_byte, msg_byte, | ||
2396 | host_byte, driver_byte); | ||
2372 | 2397 | ||
2373 | if (cmd->err_info->ScsiStatus != 0x02) { /* not check condition? */ | 2398 | if (cmd->err_info->ScsiStatus != SAM_STAT_CHECK_CONDITION) { |
2374 | if (!blk_pc_request(cmd->rq)) | 2399 | if (!blk_pc_request(cmd->rq)) |
2375 | printk(KERN_WARNING "cciss: cmd %p " | 2400 | printk(KERN_WARNING "cciss: cmd %p " |
2376 | "has SCSI Status 0x%x\n", | 2401 | "has SCSI Status 0x%x\n", |
2377 | cmd, cmd->err_info->ScsiStatus); | 2402 | cmd, cmd->err_info->ScsiStatus); |
2378 | return error_count; | 2403 | return error_value; |
2379 | } | 2404 | } |
2380 | 2405 | ||
2381 | /* check the sense key */ | 2406 | /* check the sense key */ |
2382 | sense_key = 0xf & cmd->err_info->SenseInfo[2]; | 2407 | sense_key = 0xf & cmd->err_info->SenseInfo[2]; |
2383 | /* no status or recovered error */ | 2408 | /* no status or recovered error */ |
2384 | if ((sense_key == 0x0) || (sense_key == 0x1)) | 2409 | if (((sense_key == 0x0) || (sense_key == 0x1)) && !blk_pc_request(cmd->rq)) |
2385 | error_count = 0; | 2410 | error_value = 0; |
2386 | 2411 | ||
2387 | if (!blk_pc_request(cmd->rq)) { /* Not SG_IO or similar? */ | 2412 | if (!blk_pc_request(cmd->rq)) { /* Not SG_IO or similar? */ |
2388 | if (error_count != 0) | 2413 | if (error_value != 0) |
2389 | printk(KERN_WARNING "cciss: cmd %p has CHECK CONDITION" | 2414 | printk(KERN_WARNING "cciss: cmd %p has CHECK CONDITION" |
2390 | " sense key = 0x%x\n", cmd, sense_key); | 2415 | " sense key = 0x%x\n", cmd, sense_key); |
2391 | return error_count; | 2416 | return error_value; |
2392 | } | 2417 | } |
2393 | 2418 | ||
2394 | /* SG_IO or similar, copy sense data back */ | 2419 | /* SG_IO or similar, copy sense data back */ |
@@ -2400,7 +2425,7 @@ static inline int evaluate_target_status(CommandList_struct *cmd) | |||
2400 | } else | 2425 | } else |
2401 | cmd->rq->sense_len = 0; | 2426 | cmd->rq->sense_len = 0; |
2402 | 2427 | ||
2403 | return error_count; | 2428 | return error_value; |
2404 | } | 2429 | } |
2405 | 2430 | ||
2406 | /* checks the status of the job and calls complete buffers to mark all | 2431 | /* checks the status of the job and calls complete buffers to mark all |
@@ -2416,7 +2441,7 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd, | |||
2416 | rq->errors = 0; | 2441 | rq->errors = 0; |
2417 | 2442 | ||
2418 | if (timeout) | 2443 | if (timeout) |
2419 | rq->errors = 1; | 2444 | rq->errors = make_status_bytes(0, 0, 0, DRIVER_TIMEOUT); |
2420 | 2445 | ||
2421 | if (cmd->err_info->CommandStatus == 0) /* no error has occurred */ | 2446 | if (cmd->err_info->CommandStatus == 0) /* no error has occurred */ |
2422 | goto after_error_processing; | 2447 | goto after_error_processing; |
@@ -2442,32 +2467,44 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd, | |||
2442 | case CMD_INVALID: | 2467 | case CMD_INVALID: |
2443 | printk(KERN_WARNING "cciss: cmd %p is " | 2468 | printk(KERN_WARNING "cciss: cmd %p is " |
2444 | "reported invalid\n", cmd); | 2469 | "reported invalid\n", cmd); |
2445 | rq->errors = 1; | 2470 | rq->errors = make_status_bytes(SAM_STAT_GOOD, |
2471 | cmd->err_info->CommandStatus, DRIVER_OK, | ||
2472 | blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR); | ||
2446 | break; | 2473 | break; |
2447 | case CMD_PROTOCOL_ERR: | 2474 | case CMD_PROTOCOL_ERR: |
2448 | printk(KERN_WARNING "cciss: cmd %p has " | 2475 | printk(KERN_WARNING "cciss: cmd %p has " |
2449 | "protocol error \n", cmd); | 2476 | "protocol error \n", cmd); |
2450 | rq->errors = 1; | 2477 | rq->errors = make_status_bytes(SAM_STAT_GOOD, |
2478 | cmd->err_info->CommandStatus, DRIVER_OK, | ||
2479 | blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR); | ||
2451 | break; | 2480 | break; |
2452 | case CMD_HARDWARE_ERR: | 2481 | case CMD_HARDWARE_ERR: |
2453 | printk(KERN_WARNING "cciss: cmd %p had " | 2482 | printk(KERN_WARNING "cciss: cmd %p had " |
2454 | " hardware error\n", cmd); | 2483 | " hardware error\n", cmd); |
2455 | rq->errors = 1; | 2484 | rq->errors = make_status_bytes(SAM_STAT_GOOD, |
2485 | cmd->err_info->CommandStatus, DRIVER_OK, | ||
2486 | blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR); | ||
2456 | break; | 2487 | break; |
2457 | case CMD_CONNECTION_LOST: | 2488 | case CMD_CONNECTION_LOST: |
2458 | printk(KERN_WARNING "cciss: cmd %p had " | 2489 | printk(KERN_WARNING "cciss: cmd %p had " |
2459 | "connection lost\n", cmd); | 2490 | "connection lost\n", cmd); |
2460 | rq->errors = 1; | 2491 | rq->errors = make_status_bytes(SAM_STAT_GOOD, |
2492 | cmd->err_info->CommandStatus, DRIVER_OK, | ||
2493 | blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR); | ||
2461 | break; | 2494 | break; |
2462 | case CMD_ABORTED: | 2495 | case CMD_ABORTED: |
2463 | printk(KERN_WARNING "cciss: cmd %p was " | 2496 | printk(KERN_WARNING "cciss: cmd %p was " |
2464 | "aborted\n", cmd); | 2497 | "aborted\n", cmd); |
2465 | rq->errors = 1; | 2498 | rq->errors = make_status_bytes(SAM_STAT_GOOD, |
2499 | cmd->err_info->CommandStatus, DRIVER_OK, | ||
2500 | blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ABORT); | ||
2466 | break; | 2501 | break; |
2467 | case CMD_ABORT_FAILED: | 2502 | case CMD_ABORT_FAILED: |
2468 | printk(KERN_WARNING "cciss: cmd %p reports " | 2503 | printk(KERN_WARNING "cciss: cmd %p reports " |
2469 | "abort failed\n", cmd); | 2504 | "abort failed\n", cmd); |
2470 | rq->errors = 1; | 2505 | rq->errors = make_status_bytes(SAM_STAT_GOOD, |
2506 | cmd->err_info->CommandStatus, DRIVER_OK, | ||
2507 | blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR); | ||
2471 | break; | 2508 | break; |
2472 | case CMD_UNSOLICITED_ABORT: | 2509 | case CMD_UNSOLICITED_ABORT: |
2473 | printk(KERN_WARNING "cciss%d: unsolicited " | 2510 | printk(KERN_WARNING "cciss%d: unsolicited " |
@@ -2481,17 +2518,23 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd, | |||
2481 | printk(KERN_WARNING | 2518 | printk(KERN_WARNING |
2482 | "cciss%d: %p retried too " | 2519 | "cciss%d: %p retried too " |
2483 | "many times\n", h->ctlr, cmd); | 2520 | "many times\n", h->ctlr, cmd); |
2484 | rq->errors = 1; | 2521 | rq->errors = make_status_bytes(SAM_STAT_GOOD, |
2522 | cmd->err_info->CommandStatus, DRIVER_OK, | ||
2523 | blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ABORT); | ||
2485 | break; | 2524 | break; |
2486 | case CMD_TIMEOUT: | 2525 | case CMD_TIMEOUT: |
2487 | printk(KERN_WARNING "cciss: cmd %p timedout\n", cmd); | 2526 | printk(KERN_WARNING "cciss: cmd %p timedout\n", cmd); |
2488 | rq->errors = 1; | 2527 | rq->errors = make_status_bytes(SAM_STAT_GOOD, |
2528 | cmd->err_info->CommandStatus, DRIVER_OK, | ||
2529 | blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR); | ||
2489 | break; | 2530 | break; |
2490 | default: | 2531 | default: |
2491 | printk(KERN_WARNING "cciss: cmd %p returned " | 2532 | printk(KERN_WARNING "cciss: cmd %p returned " |
2492 | "unknown status %x\n", cmd, | 2533 | "unknown status %x\n", cmd, |
2493 | cmd->err_info->CommandStatus); | 2534 | cmd->err_info->CommandStatus); |
2494 | rq->errors = 1; | 2535 | rq->errors = make_status_bytes(SAM_STAT_GOOD, |
2536 | cmd->err_info->CommandStatus, DRIVER_OK, | ||
2537 | blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR); | ||
2495 | } | 2538 | } |
2496 | 2539 | ||
2497 | after_error_processing: | 2540 | after_error_processing: |