diff options
Diffstat (limited to 'drivers/block/cciss.c')
-rw-r--r-- | drivers/block/cciss.c | 135 |
1 files changed, 88 insertions, 47 deletions
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index e330c26c5ad9..7c2cfde08f18 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -1582,38 +1582,36 @@ static int deregister_disk(struct gendisk *disk, drive_info_struct *drv, * allows us to delete disk zero but keep the controller registered. */ if (h->gendisk[0] != disk) { - if (disk) { - struct request_queue *q = disk->queue; - if (disk->flags & GENHD_FL_UP) - del_gendisk(disk); - if (q) { - blk_cleanup_queue(q); - /* Set drv->queue to NULL so that we do not try - * to call blk_start_queue on this queue in the - * interrupt handler - */ - drv->queue = NULL; - } - /* If clear_all is set then we are deleting the logical - * drive, not just refreshing its info. For drives - * other than disk 0 we will call put_disk. We do not - * do this for disk 0 as we need it to be able to - * configure the controller. + struct request_queue *q = disk->queue; + if (disk->flags & GENHD_FL_UP) + del_gendisk(disk); + if (q) { + blk_cleanup_queue(q); + /* Set drv->queue to NULL so that we do not try + * to call blk_start_queue on this queue in the + * interrupt handler + */ + drv->queue = NULL; + } + /* If clear_all is set then we are deleting the logical + * drive, not just refreshing its info. For drives + * other than disk 0 we will call put_disk. We do not + * do this for disk 0 as we need it to be able to + * configure the controller. + */ + if (clear_all){ + /* This isn't pretty, but we need to find the + * disk in our array and NULL our the pointer. + * This is so that we will call alloc_disk if + * this index is used again later. */ - if (clear_all){ - /* This isn't pretty, but we need to find the - * disk in our array and NULL our the pointer. - * This is so that we will call alloc_disk if - * this index is used again later. - */ - for (i=0; i < CISS_MAX_LUN; i++){ - if(h->gendisk[i] == disk){ - h->gendisk[i] = NULL; - break; - } + for (i=0; i < CISS_MAX_LUN; i++){ + if(h->gendisk[i] == disk){ + h->gendisk[i] = NULL; + break; } - put_disk(disk); } + put_disk(disk); } } else { set_capacity(disk, 0); @@ -2365,30 +2363,55 @@ static inline void resend_cciss_cmd(ctlr_info_t *h, CommandList_struct *c) start_io(h); } +static inline unsigned int make_status_bytes(unsigned int scsi_status_byte, + unsigned int msg_byte, unsigned int host_byte, + unsigned int driver_byte) +{ + /* inverse of macros in scsi.h */ + return (scsi_status_byte & 0xff) | + ((msg_byte & 0xff) << 8) | + ((host_byte & 0xff) << 16) | + ((driver_byte & 0xff) << 24); +} + static inline int evaluate_target_status(CommandList_struct *cmd) { unsigned char sense_key; - int error_count = 1; + unsigned char status_byte, msg_byte, host_byte, driver_byte; + int error_value; + + /* If we get in here, it means we got "target status", that is, scsi status */ + status_byte = cmd->err_info->ScsiStatus; + driver_byte = DRIVER_OK; + msg_byte = cmd->err_info->CommandStatus; /* correct? seems too device specific */ + + if (blk_pc_request(cmd->rq)) + host_byte = DID_PASSTHROUGH; + else + host_byte = DID_OK; + + error_value = make_status_bytes(status_byte, msg_byte, + host_byte, driver_byte); - if (cmd->err_info->ScsiStatus != 0x02) { /* not check condition? */ + if (cmd->err_info->ScsiStatus != SAM_STAT_CHECK_CONDITION) { if (!blk_pc_request(cmd->rq)) printk(KERN_WARNING "cciss: cmd %p " "has SCSI Status 0x%x\n", cmd, cmd->err_info->ScsiStatus); - return error_count; + return error_value; } /* check the sense key */ sense_key = 0xf & cmd->err_info->SenseInfo[2]; /* no status or recovered error */ - if ((sense_key == 0x0) || (sense_key == 0x1)) - error_count = 0; + if (((sense_key == 0x0) || (sense_key == 0x1)) && !blk_pc_request(cmd->rq)) + error_value = 0; if (!blk_pc_request(cmd->rq)) { /* Not SG_IO or similar? */ - if (error_count != 0) + if (error_value != 0) printk(KERN_WARNING "cciss: cmd %p has CHECK CONDITION" " sense key = 0x%x\n", cmd, sense_key); - return error_count; + return error_value; } /* SG_IO or similar, copy sense data back */ @@ -2400,7 +2423,7 @@ static inline int evaluate_target_status(CommandList_struct *cmd) } else cmd->rq->sense_len = 0; - return error_count; + return error_value; } /* checks the status of the job and calls complete buffers to mark all @@ -2416,7 +2439,7 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd, rq->errors = 0; if (timeout) - rq->errors = 1; + rq->errors = make_status_bytes(0, 0, 0, DRIVER_TIMEOUT); if (cmd->err_info->CommandStatus == 0) /* no error has occurred */ goto after_error_processing; @@ -2442,32 +2465,44 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd, case CMD_INVALID: printk(KERN_WARNING "cciss: cmd %p is " "reported invalid\n", cmd); - rq->errors = 1; + rq->errors = make_status_bytes(SAM_STAT_GOOD, + cmd->err_info->CommandStatus, DRIVER_OK, + blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR); break; case CMD_PROTOCOL_ERR: printk(KERN_WARNING "cciss: cmd %p has " "protocol error \n", cmd); - rq->errors = 1; + rq->errors = make_status_bytes(SAM_STAT_GOOD, + cmd->err_info->CommandStatus, DRIVER_OK, + blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR); break; case CMD_HARDWARE_ERR: printk(KERN_WARNING "cciss: cmd %p had " " hardware error\n", cmd); - rq->errors = 1; + rq->errors = make_status_bytes(SAM_STAT_GOOD, + cmd->err_info->CommandStatus, DRIVER_OK, + blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR); break; case CMD_CONNECTION_LOST: printk(KERN_WARNING "cciss: cmd %p had " "connection lost\n", cmd); - rq->errors = 1; + rq->errors = make_status_bytes(SAM_STAT_GOOD, + cmd->err_info->CommandStatus, DRIVER_OK, + blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR); break; case CMD_ABORTED: printk(KERN_WARNING "cciss: cmd %p was " "aborted\n", cmd); - rq->errors = 1; + rq->errors = make_status_bytes(SAM_STAT_GOOD, + cmd->err_info->CommandStatus, DRIVER_OK, + blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ABORT); break; case CMD_ABORT_FAILED: printk(KERN_WARNING "cciss: cmd %p reports " "abort failed\n", cmd); - rq->errors = 1; + rq->errors = make_status_bytes(SAM_STAT_GOOD, + cmd->err_info->CommandStatus, DRIVER_OK, + blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR); break; case CMD_UNSOLICITED_ABORT: printk(KERN_WARNING "cciss%d: unsolicited " @@ -2481,17 +2516,23 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd, printk(KERN_WARNING "cciss%d: %p retried too " "many times\n", h->ctlr, cmd); - rq->errors = 1; + rq->errors = make_status_bytes(SAM_STAT_GOOD, + cmd->err_info->CommandStatus, DRIVER_OK, + blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ABORT); break; case CMD_TIMEOUT: printk(KERN_WARNING "cciss: cmd %p timedout\n", cmd); - rq->errors = 1; + rq->errors = make_status_bytes(SAM_STAT_GOOD, + cmd->err_info->CommandStatus, DRIVER_OK, + blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR); break; default: printk(KERN_WARNING "cciss: cmd %p returned " "unknown status %x\n", cmd, cmd->err_info->CommandStatus); - rq->errors = 1; + rq->errors = make_status_bytes(SAM_STAT_GOOD, + cmd->err_info->CommandStatus, DRIVER_OK, + blk_pc_request(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR); } after_error_processing: |