diff options
Diffstat (limited to 'drivers/scsi/scsi_lib.c')
-rw-r--r-- | drivers/scsi/scsi_lib.c | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index fcdc585278bf..7e3d954c9cac 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c | |||
@@ -1641,6 +1641,87 @@ static void scsi_softirq_done(struct request *rq) | |||
1641 | } | 1641 | } |
1642 | 1642 | ||
1643 | /** | 1643 | /** |
1644 | * scsi_dispatch_command - Dispatch a command to the low-level driver. | ||
1645 | * @cmd: command block we are dispatching. | ||
1646 | * | ||
1647 | * Return: nonzero return request was rejected and device's queue needs to be | ||
1648 | * plugged. | ||
1649 | */ | ||
1650 | static int scsi_dispatch_cmd(struct scsi_cmnd *cmd) | ||
1651 | { | ||
1652 | struct Scsi_Host *host = cmd->device->host; | ||
1653 | int rtn = 0; | ||
1654 | |||
1655 | atomic_inc(&cmd->device->iorequest_cnt); | ||
1656 | |||
1657 | /* check if the device is still usable */ | ||
1658 | if (unlikely(cmd->device->sdev_state == SDEV_DEL)) { | ||
1659 | /* in SDEV_DEL we error all commands. DID_NO_CONNECT | ||
1660 | * returns an immediate error upwards, and signals | ||
1661 | * that the device is no longer present */ | ||
1662 | cmd->result = DID_NO_CONNECT << 16; | ||
1663 | goto done; | ||
1664 | } | ||
1665 | |||
1666 | /* Check to see if the scsi lld made this device blocked. */ | ||
1667 | if (unlikely(scsi_device_blocked(cmd->device))) { | ||
1668 | /* | ||
1669 | * in blocked state, the command is just put back on | ||
1670 | * the device queue. The suspend state has already | ||
1671 | * blocked the queue so future requests should not | ||
1672 | * occur until the device transitions out of the | ||
1673 | * suspend state. | ||
1674 | */ | ||
1675 | SCSI_LOG_MLQUEUE(3, scmd_printk(KERN_INFO, cmd, | ||
1676 | "queuecommand : device blocked\n")); | ||
1677 | return SCSI_MLQUEUE_DEVICE_BUSY; | ||
1678 | } | ||
1679 | |||
1680 | /* Store the LUN value in cmnd, if needed. */ | ||
1681 | if (cmd->device->lun_in_cdb) | ||
1682 | cmd->cmnd[1] = (cmd->cmnd[1] & 0x1f) | | ||
1683 | (cmd->device->lun << 5 & 0xe0); | ||
1684 | |||
1685 | scsi_log_send(cmd); | ||
1686 | |||
1687 | /* | ||
1688 | * Before we queue this command, check if the command | ||
1689 | * length exceeds what the host adapter can handle. | ||
1690 | */ | ||
1691 | if (cmd->cmd_len > cmd->device->host->max_cmd_len) { | ||
1692 | SCSI_LOG_MLQUEUE(3, scmd_printk(KERN_INFO, cmd, | ||
1693 | "queuecommand : command too long. " | ||
1694 | "cdb_size=%d host->max_cmd_len=%d\n", | ||
1695 | cmd->cmd_len, cmd->device->host->max_cmd_len)); | ||
1696 | cmd->result = (DID_ABORT << 16); | ||
1697 | goto done; | ||
1698 | } | ||
1699 | |||
1700 | if (unlikely(host->shost_state == SHOST_DEL)) { | ||
1701 | cmd->result = (DID_NO_CONNECT << 16); | ||
1702 | goto done; | ||
1703 | |||
1704 | } | ||
1705 | |||
1706 | trace_scsi_dispatch_cmd_start(cmd); | ||
1707 | rtn = host->hostt->queuecommand(host, cmd); | ||
1708 | if (rtn) { | ||
1709 | trace_scsi_dispatch_cmd_error(cmd, rtn); | ||
1710 | if (rtn != SCSI_MLQUEUE_DEVICE_BUSY && | ||
1711 | rtn != SCSI_MLQUEUE_TARGET_BUSY) | ||
1712 | rtn = SCSI_MLQUEUE_HOST_BUSY; | ||
1713 | |||
1714 | SCSI_LOG_MLQUEUE(3, scmd_printk(KERN_INFO, cmd, | ||
1715 | "queuecommand : request rejected\n")); | ||
1716 | } | ||
1717 | |||
1718 | return rtn; | ||
1719 | done: | ||
1720 | cmd->scsi_done(cmd); | ||
1721 | return 0; | ||
1722 | } | ||
1723 | |||
1724 | /** | ||
1644 | * scsi_done - Invoke completion on finished SCSI command. | 1725 | * scsi_done - Invoke completion on finished SCSI command. |
1645 | * @cmd: The SCSI Command for which a low-level device driver (LLDD) gives | 1726 | * @cmd: The SCSI Command for which a low-level device driver (LLDD) gives |
1646 | * ownership back to SCSI Core -- i.e. the LLDD has finished with it. | 1727 | * ownership back to SCSI Core -- i.e. the LLDD has finished with it. |