diff options
Diffstat (limited to 'drivers/block/cciss_scsi.c')
-rw-r--r-- | drivers/block/cciss_scsi.c | 85 |
1 files changed, 79 insertions, 6 deletions
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index a3fd87b41444..8575c48c8917 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c | |||
@@ -58,6 +58,18 @@ static int sendcmd( | |||
58 | unsigned char *scsi3addr, | 58 | unsigned char *scsi3addr, |
59 | int cmd_type); | 59 | int cmd_type); |
60 | 60 | ||
61 | static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, | ||
62 | size_t size, | ||
63 | unsigned int use_unit_num, /* 0: address the controller, | ||
64 | 1: address logical volume log_unit, | ||
65 | 2: periph device address is scsi3addr */ | ||
66 | unsigned int log_unit, __u8 page_code, unsigned char *scsi3addr, | ||
67 | int cmd_type); | ||
68 | |||
69 | static int sendcmd_core(ctlr_info_t *h, CommandList_struct *c); | ||
70 | |||
71 | static CommandList_struct *cmd_alloc(ctlr_info_t *h, int get_from_pool); | ||
72 | static void cmd_free(ctlr_info_t *h, CommandList_struct *c, int got_from_pool); | ||
61 | 73 | ||
62 | static int cciss_scsi_proc_info( | 74 | static int cciss_scsi_proc_info( |
63 | struct Scsi_Host *sh, | 75 | struct Scsi_Host *sh, |
@@ -1575,6 +1587,68 @@ cciss_seq_tape_report(struct seq_file *seq, int ctlr) | |||
1575 | CPQ_TAPE_UNLOCK(ctlr, flags); | 1587 | CPQ_TAPE_UNLOCK(ctlr, flags); |
1576 | } | 1588 | } |
1577 | 1589 | ||
1590 | static int wait_for_device_to_become_ready(ctlr_info_t *h, | ||
1591 | unsigned char lunaddr[]) | ||
1592 | { | ||
1593 | int rc; | ||
1594 | int count = 0; | ||
1595 | int waittime = HZ; | ||
1596 | CommandList_struct *c; | ||
1597 | |||
1598 | c = cmd_alloc(h, 1); | ||
1599 | if (!c) { | ||
1600 | printk(KERN_WARNING "cciss%d: out of memory in " | ||
1601 | "wait_for_device_to_become_ready.\n", h->ctlr); | ||
1602 | return IO_ERROR; | ||
1603 | } | ||
1604 | |||
1605 | /* Send test unit ready until device ready, or give up. */ | ||
1606 | while (count < 20) { | ||
1607 | |||
1608 | /* Wait for a bit. do this first, because if we send | ||
1609 | * the TUR right away, the reset will just abort it. | ||
1610 | */ | ||
1611 | set_current_state(TASK_INTERRUPTIBLE); | ||
1612 | schedule_timeout(waittime); | ||
1613 | count++; | ||
1614 | |||
1615 | /* Increase wait time with each try, up to a point. */ | ||
1616 | if (waittime < (HZ * 30)) | ||
1617 | waittime = waittime * 2; | ||
1618 | |||
1619 | /* Send the Test Unit Ready */ | ||
1620 | rc = fill_cmd(c, TEST_UNIT_READY, h->ctlr, NULL, 0, 0, 0, 0, | ||
1621 | lunaddr, TYPE_CMD); | ||
1622 | if (rc == 0) { | ||
1623 | rc = sendcmd_core(h, c); | ||
1624 | /* sendcmd turned off interrupts, turn 'em back on. */ | ||
1625 | h->access.set_intr_mask(h, CCISS_INTR_ON); | ||
1626 | } | ||
1627 | |||
1628 | if (rc == 0 && c->err_info->CommandStatus == CMD_SUCCESS) | ||
1629 | break; | ||
1630 | |||
1631 | if (rc == 0 && | ||
1632 | c->err_info->CommandStatus == CMD_TARGET_STATUS && | ||
1633 | c->err_info->ScsiStatus == SAM_STAT_CHECK_CONDITION && | ||
1634 | (c->err_info->SenseInfo[2] == NO_SENSE || | ||
1635 | c->err_info->SenseInfo[2] == UNIT_ATTENTION)) | ||
1636 | break; | ||
1637 | |||
1638 | printk(KERN_WARNING "cciss%d: Waiting %d secs " | ||
1639 | "for device to become ready.\n", | ||
1640 | h->ctlr, waittime / HZ); | ||
1641 | rc = 1; /* device not ready. */ | ||
1642 | } | ||
1643 | |||
1644 | if (rc) | ||
1645 | printk("cciss%d: giving up on device.\n", h->ctlr); | ||
1646 | else | ||
1647 | printk(KERN_WARNING "cciss%d: device is ready.\n", h->ctlr); | ||
1648 | |||
1649 | cmd_free(h, c, 1); | ||
1650 | return rc; | ||
1651 | } | ||
1578 | 1652 | ||
1579 | /* Need at least one of these error handlers to keep ../scsi/hosts.c from | 1653 | /* Need at least one of these error handlers to keep ../scsi/hosts.c from |
1580 | * complaining. Doing a host- or bus-reset can't do anything good here. | 1654 | * complaining. Doing a host- or bus-reset can't do anything good here. |
@@ -1591,6 +1665,7 @@ static int cciss_eh_device_reset_handler(struct scsi_cmnd *scsicmd) | |||
1591 | { | 1665 | { |
1592 | int rc; | 1666 | int rc; |
1593 | CommandList_struct *cmd_in_trouble; | 1667 | CommandList_struct *cmd_in_trouble; |
1668 | unsigned char lunaddr[8]; | ||
1594 | ctlr_info_t **c; | 1669 | ctlr_info_t **c; |
1595 | int ctlr; | 1670 | int ctlr; |
1596 | 1671 | ||
@@ -1600,19 +1675,17 @@ static int cciss_eh_device_reset_handler(struct scsi_cmnd *scsicmd) | |||
1600 | return FAILED; | 1675 | return FAILED; |
1601 | ctlr = (*c)->ctlr; | 1676 | ctlr = (*c)->ctlr; |
1602 | printk(KERN_WARNING "cciss%d: resetting tape drive or medium changer.\n", ctlr); | 1677 | printk(KERN_WARNING "cciss%d: resetting tape drive or medium changer.\n", ctlr); |
1603 | |||
1604 | /* find the command that's giving us trouble */ | 1678 | /* find the command that's giving us trouble */ |
1605 | cmd_in_trouble = (CommandList_struct *) scsicmd->host_scribble; | 1679 | cmd_in_trouble = (CommandList_struct *) scsicmd->host_scribble; |
1606 | if (cmd_in_trouble == NULL) { /* paranoia */ | 1680 | if (cmd_in_trouble == NULL) /* paranoia */ |
1607 | return FAILED; | 1681 | return FAILED; |
1608 | } | 1682 | memcpy(lunaddr, &cmd_in_trouble->Header.LUN.LunAddrBytes[0], 8); |
1609 | /* send a reset to the SCSI LUN which the command was sent to */ | 1683 | /* send a reset to the SCSI LUN which the command was sent to */ |
1610 | rc = sendcmd(CCISS_RESET_MSG, ctlr, NULL, 0, 2, 0, 0, | 1684 | rc = sendcmd(CCISS_RESET_MSG, ctlr, NULL, 0, 2, 0, 0, lunaddr, |
1611 | (unsigned char *) &cmd_in_trouble->Header.LUN.LunAddrBytes[0], | ||
1612 | TYPE_MSG); | 1685 | TYPE_MSG); |
1613 | /* sendcmd turned off interrupts on the board, turn 'em back on. */ | 1686 | /* sendcmd turned off interrupts on the board, turn 'em back on. */ |
1614 | (*c)->access.set_intr_mask(*c, CCISS_INTR_ON); | 1687 | (*c)->access.set_intr_mask(*c, CCISS_INTR_ON); |
1615 | if (rc == 0) | 1688 | if (rc == 0 && wait_for_device_to_become_ready(*c, lunaddr) == 0) |
1616 | return SUCCESS; | 1689 | return SUCCESS; |
1617 | printk(KERN_WARNING "cciss%d: resetting device failed.\n", ctlr); | 1690 | printk(KERN_WARNING "cciss%d: resetting device failed.\n", ctlr); |
1618 | return FAILED; | 1691 | return FAILED; |