diff options
Diffstat (limited to 'drivers/block/cciss_scsi.c')
-rw-r--r-- | drivers/block/cciss_scsi.c | 109 |
1 files changed, 83 insertions, 26 deletions
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index a3fd87b41444..3315268b4ec7 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c | |||
@@ -44,20 +44,13 @@ | |||
44 | #define CCISS_ABORT_MSG 0x00 | 44 | #define CCISS_ABORT_MSG 0x00 |
45 | #define CCISS_RESET_MSG 0x01 | 45 | #define CCISS_RESET_MSG 0x01 |
46 | 46 | ||
47 | /* some prototypes... */ | 47 | static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, |
48 | static int sendcmd( | 48 | size_t size, |
49 | __u8 cmd, | 49 | __u8 page_code, unsigned char *scsi3addr, |
50 | int ctlr, | ||
51 | void *buff, | ||
52 | size_t size, | ||
53 | unsigned int use_unit_num, /* 0: address the controller, | ||
54 | 1: address logical volume log_unit, | ||
55 | 2: address is in scsi3addr */ | ||
56 | unsigned int log_unit, | ||
57 | __u8 page_code, | ||
58 | unsigned char *scsi3addr, | ||
59 | int cmd_type); | 50 | int cmd_type); |
60 | 51 | ||
52 | static CommandList_struct *cmd_alloc(ctlr_info_t *h, int get_from_pool); | ||
53 | static void cmd_free(ctlr_info_t *h, CommandList_struct *c, int got_from_pool); | ||
61 | 54 | ||
62 | static int cciss_scsi_proc_info( | 55 | static int cciss_scsi_proc_info( |
63 | struct Scsi_Host *sh, | 56 | struct Scsi_Host *sh, |
@@ -1575,6 +1568,75 @@ cciss_seq_tape_report(struct seq_file *seq, int ctlr) | |||
1575 | CPQ_TAPE_UNLOCK(ctlr, flags); | 1568 | CPQ_TAPE_UNLOCK(ctlr, flags); |
1576 | } | 1569 | } |
1577 | 1570 | ||
1571 | static int wait_for_device_to_become_ready(ctlr_info_t *h, | ||
1572 | unsigned char lunaddr[]) | ||
1573 | { | ||
1574 | int rc; | ||
1575 | int count = 0; | ||
1576 | int waittime = HZ; | ||
1577 | CommandList_struct *c; | ||
1578 | |||
1579 | c = cmd_alloc(h, 1); | ||
1580 | if (!c) { | ||
1581 | printk(KERN_WARNING "cciss%d: out of memory in " | ||
1582 | "wait_for_device_to_become_ready.\n", h->ctlr); | ||
1583 | return IO_ERROR; | ||
1584 | } | ||
1585 | |||
1586 | /* Send test unit ready until device ready, or give up. */ | ||
1587 | while (count < 20) { | ||
1588 | |||
1589 | /* Wait for a bit. do this first, because if we send | ||
1590 | * the TUR right away, the reset will just abort it. | ||
1591 | */ | ||
1592 | schedule_timeout_uninterruptible(waittime); | ||
1593 | count++; | ||
1594 | |||
1595 | /* Increase wait time with each try, up to a point. */ | ||
1596 | if (waittime < (HZ * 30)) | ||
1597 | waittime = waittime * 2; | ||
1598 | |||
1599 | /* Send the Test Unit Ready */ | ||
1600 | rc = fill_cmd(c, TEST_UNIT_READY, h->ctlr, NULL, 0, 0, | ||
1601 | lunaddr, TYPE_CMD); | ||
1602 | if (rc == 0) | ||
1603 | rc = sendcmd_withirq_core(h, c, 0); | ||
1604 | |||
1605 | (void) process_sendcmd_error(h, c); | ||
1606 | |||
1607 | if (rc != 0) | ||
1608 | goto retry_tur; | ||
1609 | |||
1610 | if (c->err_info->CommandStatus == CMD_SUCCESS) | ||
1611 | break; | ||
1612 | |||
1613 | if (c->err_info->CommandStatus == CMD_TARGET_STATUS && | ||
1614 | c->err_info->ScsiStatus == SAM_STAT_CHECK_CONDITION) { | ||
1615 | if (c->err_info->SenseInfo[2] == NO_SENSE) | ||
1616 | break; | ||
1617 | if (c->err_info->SenseInfo[2] == UNIT_ATTENTION) { | ||
1618 | unsigned char asc; | ||
1619 | asc = c->err_info->SenseInfo[12]; | ||
1620 | check_for_unit_attention(h, c); | ||
1621 | if (asc == POWER_OR_RESET) | ||
1622 | break; | ||
1623 | } | ||
1624 | } | ||
1625 | retry_tur: | ||
1626 | printk(KERN_WARNING "cciss%d: Waiting %d secs " | ||
1627 | "for device to become ready.\n", | ||
1628 | h->ctlr, waittime / HZ); | ||
1629 | rc = 1; /* device not ready. */ | ||
1630 | } | ||
1631 | |||
1632 | if (rc) | ||
1633 | printk("cciss%d: giving up on device.\n", h->ctlr); | ||
1634 | else | ||
1635 | printk(KERN_WARNING "cciss%d: device is ready.\n", h->ctlr); | ||
1636 | |||
1637 | cmd_free(h, c, 1); | ||
1638 | return rc; | ||
1639 | } | ||
1578 | 1640 | ||
1579 | /* Need at least one of these error handlers to keep ../scsi/hosts.c from | 1641 | /* 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. | 1642 | * complaining. Doing a host- or bus-reset can't do anything good here. |
@@ -1591,6 +1653,7 @@ static int cciss_eh_device_reset_handler(struct scsi_cmnd *scsicmd) | |||
1591 | { | 1653 | { |
1592 | int rc; | 1654 | int rc; |
1593 | CommandList_struct *cmd_in_trouble; | 1655 | CommandList_struct *cmd_in_trouble; |
1656 | unsigned char lunaddr[8]; | ||
1594 | ctlr_info_t **c; | 1657 | ctlr_info_t **c; |
1595 | int ctlr; | 1658 | int ctlr; |
1596 | 1659 | ||
@@ -1600,19 +1663,15 @@ static int cciss_eh_device_reset_handler(struct scsi_cmnd *scsicmd) | |||
1600 | return FAILED; | 1663 | return FAILED; |
1601 | ctlr = (*c)->ctlr; | 1664 | ctlr = (*c)->ctlr; |
1602 | printk(KERN_WARNING "cciss%d: resetting tape drive or medium changer.\n", ctlr); | 1665 | printk(KERN_WARNING "cciss%d: resetting tape drive or medium changer.\n", ctlr); |
1603 | |||
1604 | /* find the command that's giving us trouble */ | 1666 | /* find the command that's giving us trouble */ |
1605 | cmd_in_trouble = (CommandList_struct *) scsicmd->host_scribble; | 1667 | cmd_in_trouble = (CommandList_struct *) scsicmd->host_scribble; |
1606 | if (cmd_in_trouble == NULL) { /* paranoia */ | 1668 | if (cmd_in_trouble == NULL) /* paranoia */ |
1607 | return FAILED; | 1669 | return FAILED; |
1608 | } | 1670 | memcpy(lunaddr, &cmd_in_trouble->Header.LUN.LunAddrBytes[0], 8); |
1609 | /* send a reset to the SCSI LUN which the command was sent to */ | 1671 | /* 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, | 1672 | rc = sendcmd_withirq(CCISS_RESET_MSG, ctlr, NULL, 0, 0, lunaddr, |
1611 | (unsigned char *) &cmd_in_trouble->Header.LUN.LunAddrBytes[0], | ||
1612 | TYPE_MSG); | 1673 | TYPE_MSG); |
1613 | /* sendcmd turned off interrupts on the board, turn 'em back on. */ | 1674 | if (rc == 0 && wait_for_device_to_become_ready(*c, lunaddr) == 0) |
1614 | (*c)->access.set_intr_mask(*c, CCISS_INTR_ON); | ||
1615 | if (rc == 0) | ||
1616 | return SUCCESS; | 1675 | return SUCCESS; |
1617 | printk(KERN_WARNING "cciss%d: resetting device failed.\n", ctlr); | 1676 | printk(KERN_WARNING "cciss%d: resetting device failed.\n", ctlr); |
1618 | return FAILED; | 1677 | return FAILED; |
@@ -1622,6 +1681,7 @@ static int cciss_eh_abort_handler(struct scsi_cmnd *scsicmd) | |||
1622 | { | 1681 | { |
1623 | int rc; | 1682 | int rc; |
1624 | CommandList_struct *cmd_to_abort; | 1683 | CommandList_struct *cmd_to_abort; |
1684 | unsigned char lunaddr[8]; | ||
1625 | ctlr_info_t **c; | 1685 | ctlr_info_t **c; |
1626 | int ctlr; | 1686 | int ctlr; |
1627 | 1687 | ||
@@ -1636,12 +1696,9 @@ static int cciss_eh_abort_handler(struct scsi_cmnd *scsicmd) | |||
1636 | cmd_to_abort = (CommandList_struct *) scsicmd->host_scribble; | 1696 | cmd_to_abort = (CommandList_struct *) scsicmd->host_scribble; |
1637 | if (cmd_to_abort == NULL) /* paranoia */ | 1697 | if (cmd_to_abort == NULL) /* paranoia */ |
1638 | return FAILED; | 1698 | return FAILED; |
1639 | rc = sendcmd(CCISS_ABORT_MSG, ctlr, &cmd_to_abort->Header.Tag, | 1699 | memcpy(lunaddr, &cmd_to_abort->Header.LUN.LunAddrBytes[0], 8); |
1640 | 0, 2, 0, 0, | 1700 | rc = sendcmd_withirq(CCISS_ABORT_MSG, ctlr, &cmd_to_abort->Header.Tag, |
1641 | (unsigned char *) &cmd_to_abort->Header.LUN.LunAddrBytes[0], | 1701 | 0, 0, lunaddr, TYPE_MSG); |
1642 | TYPE_MSG); | ||
1643 | /* sendcmd turned off interrupts on the board, turn 'em back on. */ | ||
1644 | (*c)->access.set_intr_mask(*c, CCISS_INTR_ON); | ||
1645 | if (rc == 0) | 1702 | if (rc == 0) |
1646 | return SUCCESS; | 1703 | return SUCCESS; |
1647 | return FAILED; | 1704 | return FAILED; |