diff options
author | Douglas Gilbert <dougg@torque.net> | 2005-10-28 15:58:28 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-10-28 15:58:28 -0400 |
commit | 00ac37f508689da281586c7ef304f26b5138d8a6 (patch) | |
tree | 409c2367a5630d860fa0d30b60c1fc6ea9ad659f /drivers/scsi/libata-scsi.c | |
parent | a21a84a375ea3783cf9a53730d643c4db24371bc (diff) |
[libata scsi] MODE SELECT, strengthen mode sense
- move default mode pages to the front of libata-scsi.c
so various functions can access them
- partial annotation of these pages, point out divergence
from sat-r06
- replace various mode page magic numbers with defines
- strengthen MODE SENSE command decoding: handle DBD
bit in cdb, yield block descriptor (per sat-r06) and
handle mode sub pages
Signed-off-by: Douglas Gilbert <dougg@torque.net>
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
Diffstat (limited to 'drivers/scsi/libata-scsi.c')
-rw-r--r-- | drivers/scsi/libata-scsi.c | 144 |
1 files changed, 103 insertions, 41 deletions
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index b761bd1b9717..89a04b1a5a0e 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c | |||
@@ -51,6 +51,45 @@ typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc, const u8 *scs | |||
51 | static struct ata_device * | 51 | static struct ata_device * |
52 | ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev); | 52 | ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev); |
53 | 53 | ||
54 | #define RW_RECOVERY_MPAGE 0x1 | ||
55 | #define RW_RECOVERY_MPAGE_LEN 12 | ||
56 | #define CACHE_MPAGE 0x8 | ||
57 | #define CACHE_MPAGE_LEN 20 | ||
58 | #define CONTROL_MPAGE 0xa | ||
59 | #define CONTROL_MPAGE_LEN 12 | ||
60 | #define ALL_MPAGES 0x3f | ||
61 | #define ALL_SUB_MPAGES 0xff | ||
62 | |||
63 | |||
64 | static const u8 def_rw_recovery_mpage[] = { | ||
65 | RW_RECOVERY_MPAGE, | ||
66 | RW_RECOVERY_MPAGE_LEN - 2, | ||
67 | (1 << 7) | /* AWRE, sat-r06 say it shall be 0 */ | ||
68 | (1 << 6), /* ARRE (auto read reallocation) */ | ||
69 | 0, /* read retry count */ | ||
70 | 0, 0, 0, 0, | ||
71 | 0, /* write retry count */ | ||
72 | 0, 0, 0 | ||
73 | }; | ||
74 | |||
75 | static const u8 def_cache_mpage[CACHE_MPAGE_LEN] = { | ||
76 | CACHE_MPAGE, | ||
77 | CACHE_MPAGE_LEN - 2, | ||
78 | 0, /* contains WCE, needs to be 0 for logic */ | ||
79 | 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
80 | 0, /* contains DRA, needs to be 0 for logic */ | ||
81 | 0, 0, 0, 0, 0, 0, 0 | ||
82 | }; | ||
83 | |||
84 | static const u8 def_control_mpage[CONTROL_MPAGE_LEN] = { | ||
85 | CONTROL_MPAGE, | ||
86 | CONTROL_MPAGE_LEN - 2, | ||
87 | 2, /* DSENSE=0, GLTSD=1 */ | ||
88 | 0, /* [QAM+QERR may be 1, see 05-359r1] */ | ||
89 | 0, 0, 0, 0, 0xff, 0xff, | ||
90 | 0, 30 /* extended self test time, see 05-359r1 */ | ||
91 | }; | ||
92 | |||
54 | 93 | ||
55 | static void ata_scsi_invalid_field(struct scsi_cmnd *cmd, | 94 | static void ata_scsi_invalid_field(struct scsi_cmnd *cmd, |
56 | void (*done)(struct scsi_cmnd *)) | 95 | void (*done)(struct scsi_cmnd *)) |
@@ -1583,13 +1622,9 @@ static void ata_msense_push(u8 **ptr_io, const u8 *last, | |||
1583 | static unsigned int ata_msense_caching(u16 *id, u8 **ptr_io, | 1622 | static unsigned int ata_msense_caching(u16 *id, u8 **ptr_io, |
1584 | const u8 *last) | 1623 | const u8 *last) |
1585 | { | 1624 | { |
1586 | u8 page[] = { | 1625 | u8 page[CACHE_MPAGE_LEN]; |
1587 | 0x8, /* page code */ | ||
1588 | 0x12, /* page length */ | ||
1589 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 zeroes */ | ||
1590 | 0, 0, 0, 0, 0, 0, 0, 0 /* 8 zeroes */ | ||
1591 | }; | ||
1592 | 1626 | ||
1627 | memcpy(page, def_cache_mpage, sizeof(page)); | ||
1593 | if (ata_id_wcache_enabled(id)) | 1628 | if (ata_id_wcache_enabled(id)) |
1594 | page[2] |= (1 << 2); /* write cache enable */ | 1629 | page[2] |= (1 << 2); /* write cache enable */ |
1595 | if (!ata_id_rahead_enabled(id)) | 1630 | if (!ata_id_rahead_enabled(id)) |
@@ -1613,15 +1648,9 @@ static unsigned int ata_msense_caching(u16 *id, u8 **ptr_io, | |||
1613 | 1648 | ||
1614 | static unsigned int ata_msense_ctl_mode(u8 **ptr_io, const u8 *last) | 1649 | static unsigned int ata_msense_ctl_mode(u8 **ptr_io, const u8 *last) |
1615 | { | 1650 | { |
1616 | const u8 page[] = {0xa, 0xa, 6, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 30}; | 1651 | ata_msense_push(ptr_io, last, def_control_mpage, |
1617 | 1652 | sizeof(def_control_mpage)); | |
1618 | /* byte 2: set the descriptor format sense data bit (bit 2) | 1653 | return sizeof(def_control_mpage); |
1619 | * since we need to support returning this format for SAT | ||
1620 | * commands and any SCSI commands against a 48b LBA device. | ||
1621 | */ | ||
1622 | |||
1623 | ata_msense_push(ptr_io, last, page, sizeof(page)); | ||
1624 | return sizeof(page); | ||
1625 | } | 1654 | } |
1626 | 1655 | ||
1627 | /** | 1656 | /** |
@@ -1638,15 +1667,10 @@ static unsigned int ata_msense_ctl_mode(u8 **ptr_io, const u8 *last) | |||
1638 | 1667 | ||
1639 | static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last) | 1668 | static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last) |
1640 | { | 1669 | { |
1641 | const u8 page[] = { | ||
1642 | 0x1, /* page code */ | ||
1643 | 0xa, /* page length */ | ||
1644 | (1 << 7) | (1 << 6), /* note auto r/w reallocation */ | ||
1645 | 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 9 zeroes */ | ||
1646 | }; | ||
1647 | 1670 | ||
1648 | ata_msense_push(ptr_io, last, page, sizeof(page)); | 1671 | ata_msense_push(ptr_io, last, def_rw_recovery_mpage, |
1649 | return sizeof(page); | 1672 | sizeof(def_rw_recovery_mpage)); |
1673 | return sizeof(def_rw_recovery_mpage); | ||
1650 | } | 1674 | } |
1651 | 1675 | ||
1652 | /** | 1676 | /** |
@@ -1655,7 +1679,9 @@ static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last) | |||
1655 | * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. | 1679 | * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. |
1656 | * @buflen: Response buffer length. | 1680 | * @buflen: Response buffer length. |
1657 | * | 1681 | * |
1658 | * Simulate MODE SENSE commands. | 1682 | * Simulate MODE SENSE commands. Assume this is invoked for direct |
1683 | * access devices (e.g. disks) only. There should be no block | ||
1684 | * descriptor for other device types. | ||
1659 | * | 1685 | * |
1660 | * LOCKING: | 1686 | * LOCKING: |
1661 | * spin_lock_irqsave(host_set lock) | 1687 | * spin_lock_irqsave(host_set lock) |
@@ -1665,15 +1691,22 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, | |||
1665 | unsigned int buflen) | 1691 | unsigned int buflen) |
1666 | { | 1692 | { |
1667 | u8 *scsicmd = args->cmd->cmnd, *p, *last; | 1693 | u8 *scsicmd = args->cmd->cmnd, *p, *last; |
1668 | unsigned int page_control, six_byte, output_len; | 1694 | const u8 sat_blk_desc[] = { |
1695 | 0, 0, 0, 0, /* number of blocks: sat unspecified */ | ||
1696 | 0, | ||
1697 | 0, 0x2, 0x0 /* block length: 512 bytes */ | ||
1698 | }; | ||
1699 | u8 pg, spg; | ||
1700 | unsigned int ebd, page_control, six_byte, output_len, alloc_len, minlen; | ||
1669 | 1701 | ||
1670 | VPRINTK("ENTER\n"); | 1702 | VPRINTK("ENTER\n"); |
1671 | 1703 | ||
1672 | six_byte = (scsicmd[0] == MODE_SENSE); | 1704 | six_byte = (scsicmd[0] == MODE_SENSE); |
1673 | 1705 | ebd = !(scsicmd[1] & 0x8); /* dbd bit inverted == edb */ | |
1674 | /* we only support saved and current values (which we treat | 1706 | /* |
1675 | * in the same manner) | 1707 | * LLBA bit in msense(10) ignored (compliant) |
1676 | */ | 1708 | */ |
1709 | |||
1677 | page_control = scsicmd[2] >> 6; | 1710 | page_control = scsicmd[2] >> 6; |
1678 | switch (page_control) { | 1711 | switch (page_control) { |
1679 | case 0: /* current */ | 1712 | case 0: /* current */ |
@@ -1686,29 +1719,42 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, | |||
1686 | goto invalid_fld; | 1719 | goto invalid_fld; |
1687 | } | 1720 | } |
1688 | 1721 | ||
1689 | if (six_byte) | 1722 | if (six_byte) { |
1690 | output_len = 4; | 1723 | output_len = 4 + (ebd ? 8 : 0); |
1691 | else | 1724 | alloc_len = scsicmd[4]; |
1692 | output_len = 8; | 1725 | } else { |
1726 | output_len = 8 + (ebd ? 8 : 0); | ||
1727 | alloc_len = (scsicmd[7] << 8) + scsicmd[8]; | ||
1728 | } | ||
1729 | minlen = (alloc_len < buflen) ? alloc_len : buflen; | ||
1693 | 1730 | ||
1694 | p = rbuf + output_len; | 1731 | p = rbuf + output_len; |
1695 | last = rbuf + buflen - 1; | 1732 | last = rbuf + minlen - 1; |
1696 | 1733 | ||
1697 | switch(scsicmd[2] & 0x3f) { | 1734 | pg = scsicmd[2] & 0x3f; |
1698 | case 0x01: /* r/w error recovery */ | 1735 | spg = scsicmd[3]; |
1736 | /* | ||
1737 | * No mode subpages supported (yet) but asking for _all_ | ||
1738 | * subpages may be valid | ||
1739 | */ | ||
1740 | if (spg && (spg != ALL_SUB_MPAGES)) | ||
1741 | goto invalid_fld; | ||
1742 | |||
1743 | switch(pg) { | ||
1744 | case RW_RECOVERY_MPAGE: | ||
1699 | output_len += ata_msense_rw_recovery(&p, last); | 1745 | output_len += ata_msense_rw_recovery(&p, last); |
1700 | break; | 1746 | break; |
1701 | 1747 | ||
1702 | case 0x08: /* caching */ | 1748 | case CACHE_MPAGE: |
1703 | output_len += ata_msense_caching(args->id, &p, last); | 1749 | output_len += ata_msense_caching(args->id, &p, last); |
1704 | break; | 1750 | break; |
1705 | 1751 | ||
1706 | case 0x0a: { /* control mode */ | 1752 | case CONTROL_MPAGE: { |
1707 | output_len += ata_msense_ctl_mode(&p, last); | 1753 | output_len += ata_msense_ctl_mode(&p, last); |
1708 | break; | 1754 | break; |
1709 | } | 1755 | } |
1710 | 1756 | ||
1711 | case 0x3f: /* all pages */ | 1757 | case ALL_MPAGES: |
1712 | output_len += ata_msense_rw_recovery(&p, last); | 1758 | output_len += ata_msense_rw_recovery(&p, last); |
1713 | output_len += ata_msense_caching(args->id, &p, last); | 1759 | output_len += ata_msense_caching(args->id, &p, last); |
1714 | output_len += ata_msense_ctl_mode(&p, last); | 1760 | output_len += ata_msense_ctl_mode(&p, last); |
@@ -1718,15 +1764,31 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, | |||
1718 | goto invalid_fld; | 1764 | goto invalid_fld; |
1719 | } | 1765 | } |
1720 | 1766 | ||
1767 | if (minlen < 1) | ||
1768 | return 0; | ||
1721 | if (six_byte) { | 1769 | if (six_byte) { |
1722 | output_len--; | 1770 | output_len--; |
1723 | rbuf[0] = output_len; | 1771 | rbuf[0] = output_len; |
1772 | if (ebd) { | ||
1773 | if (minlen > 3) | ||
1774 | rbuf[3] = sizeof(sat_blk_desc); | ||
1775 | if (minlen > 11) | ||
1776 | memcpy(rbuf + 4, sat_blk_desc, | ||
1777 | sizeof(sat_blk_desc)); | ||
1778 | } | ||
1724 | } else { | 1779 | } else { |
1725 | output_len -= 2; | 1780 | output_len -= 2; |
1726 | rbuf[0] = output_len >> 8; | 1781 | rbuf[0] = output_len >> 8; |
1727 | rbuf[1] = output_len; | 1782 | if (minlen > 1) |
1783 | rbuf[1] = output_len; | ||
1784 | if (ebd) { | ||
1785 | if (minlen > 7) | ||
1786 | rbuf[7] = sizeof(sat_blk_desc); | ||
1787 | if (minlen > 15) | ||
1788 | memcpy(rbuf + 8, sat_blk_desc, | ||
1789 | sizeof(sat_blk_desc)); | ||
1790 | } | ||
1728 | } | 1791 | } |
1729 | |||
1730 | return 0; | 1792 | return 0; |
1731 | 1793 | ||
1732 | invalid_fld: | 1794 | invalid_fld: |
@@ -2156,7 +2218,7 @@ ata_scsi_map_proto(u8 byte1) | |||
2156 | * Zero on success, non-zero on failure. | 2218 | * Zero on success, non-zero on failure. |
2157 | */ | 2219 | */ |
2158 | static unsigned int | 2220 | static unsigned int |
2159 | ata_scsi_pass_thru(struct ata_queued_cmd *qc, u8 *scsicmd) | 2221 | ata_scsi_pass_thru(struct ata_queued_cmd *qc, const u8 *scsicmd) |
2160 | { | 2222 | { |
2161 | struct ata_taskfile *tf = &(qc->tf); | 2223 | struct ata_taskfile *tf = &(qc->tf); |
2162 | struct scsi_cmnd *cmd = qc->scsicmd; | 2224 | struct scsi_cmnd *cmd = qc->scsicmd; |