diff options
| -rw-r--r-- | drivers/scsi/scsi_lib.c | 81 | ||||
| -rw-r--r-- | include/scsi/scsi_device.h | 5 |
2 files changed, 85 insertions, 1 deletions
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 9a05076f9cf4..ede158d08d9d 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c | |||
| @@ -1811,6 +1811,84 @@ void scsi_exit_queue(void) | |||
| 1811 | kmem_cache_destroy(sgp->slab); | 1811 | kmem_cache_destroy(sgp->slab); |
| 1812 | } | 1812 | } |
| 1813 | } | 1813 | } |
| 1814 | |||
| 1815 | /** | ||
| 1816 | * scsi_mode_select - issue a mode select | ||
| 1817 | * @sdev: SCSI device to be queried | ||
| 1818 | * @pf: Page format bit (1 == standard, 0 == vendor specific) | ||
| 1819 | * @sp: Save page bit (0 == don't save, 1 == save) | ||
| 1820 | * @modepage: mode page being requested | ||
| 1821 | * @buffer: request buffer (may not be smaller than eight bytes) | ||
| 1822 | * @len: length of request buffer. | ||
| 1823 | * @timeout: command timeout | ||
| 1824 | * @retries: number of retries before failing | ||
| 1825 | * @data: returns a structure abstracting the mode header data | ||
| 1826 | * @sense: place to put sense data (or NULL if no sense to be collected). | ||
| 1827 | * must be SCSI_SENSE_BUFFERSIZE big. | ||
| 1828 | * | ||
| 1829 | * Returns zero if successful; negative error number or scsi | ||
| 1830 | * status on error | ||
| 1831 | * | ||
| 1832 | */ | ||
| 1833 | int | ||
| 1834 | scsi_mode_select(struct scsi_device *sdev, int pf, int sp, int modepage, | ||
| 1835 | unsigned char *buffer, int len, int timeout, int retries, | ||
| 1836 | struct scsi_mode_data *data, struct scsi_sense_hdr *sshdr) | ||
| 1837 | { | ||
| 1838 | unsigned char cmd[10]; | ||
| 1839 | unsigned char *real_buffer; | ||
| 1840 | int ret; | ||
| 1841 | |||
| 1842 | memset(cmd, 0, sizeof(cmd)); | ||
| 1843 | cmd[1] = (pf ? 0x10 : 0) | (sp ? 0x01 : 0); | ||
| 1844 | |||
| 1845 | if (sdev->use_10_for_ms) { | ||
| 1846 | if (len > 65535) | ||
| 1847 | return -EINVAL; | ||
| 1848 | real_buffer = kmalloc(8 + len, GFP_KERNEL); | ||
| 1849 | if (!real_buffer) | ||
| 1850 | return -ENOMEM; | ||
| 1851 | memcpy(real_buffer + 8, buffer, len); | ||
| 1852 | len += 8; | ||
| 1853 | real_buffer[0] = 0; | ||
| 1854 | real_buffer[1] = 0; | ||
| 1855 | real_buffer[2] = data->medium_type; | ||
| 1856 | real_buffer[3] = data->device_specific; | ||
| 1857 | real_buffer[4] = data->longlba ? 0x01 : 0; | ||
| 1858 | real_buffer[5] = 0; | ||
| 1859 | real_buffer[6] = data->block_descriptor_length >> 8; | ||
| 1860 | real_buffer[7] = data->block_descriptor_length; | ||
| 1861 | |||
| 1862 | cmd[0] = MODE_SELECT_10; | ||
| 1863 | cmd[7] = len >> 8; | ||
| 1864 | cmd[8] = len; | ||
| 1865 | } else { | ||
| 1866 | if (len > 255 || data->block_descriptor_length > 255 || | ||
| 1867 | data->longlba) | ||
| 1868 | return -EINVAL; | ||
| 1869 | |||
| 1870 | real_buffer = kmalloc(4 + len, GFP_KERNEL); | ||
| 1871 | if (!real_buffer) | ||
| 1872 | return -ENOMEM; | ||
| 1873 | memcpy(real_buffer + 4, buffer, len); | ||
| 1874 | len += 4; | ||
| 1875 | real_buffer[0] = 0; | ||
| 1876 | real_buffer[1] = data->medium_type; | ||
| 1877 | real_buffer[2] = data->device_specific; | ||
| 1878 | real_buffer[3] = data->block_descriptor_length; | ||
| 1879 | |||
| 1880 | |||
| 1881 | cmd[0] = MODE_SELECT; | ||
| 1882 | cmd[4] = len; | ||
| 1883 | } | ||
| 1884 | |||
| 1885 | ret = scsi_execute_req(sdev, cmd, DMA_TO_DEVICE, real_buffer, len, | ||
| 1886 | sshdr, timeout, retries); | ||
| 1887 | kfree(real_buffer); | ||
| 1888 | return ret; | ||
| 1889 | } | ||
| 1890 | EXPORT_SYMBOL_GPL(scsi_mode_select); | ||
| 1891 | |||
| 1814 | /** | 1892 | /** |
| 1815 | * scsi_mode_sense - issue a mode sense, falling back from 10 to | 1893 | * scsi_mode_sense - issue a mode sense, falling back from 10 to |
| 1816 | * six bytes if necessary. | 1894 | * six bytes if necessary. |
| @@ -1832,7 +1910,8 @@ void scsi_exit_queue(void) | |||
| 1832 | int | 1910 | int |
| 1833 | scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, | 1911 | scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, |
| 1834 | unsigned char *buffer, int len, int timeout, int retries, | 1912 | unsigned char *buffer, int len, int timeout, int retries, |
| 1835 | struct scsi_mode_data *data, struct scsi_sense_hdr *sshdr) { | 1913 | struct scsi_mode_data *data, struct scsi_sense_hdr *sshdr) |
| 1914 | { | ||
| 1836 | unsigned char cmd[12]; | 1915 | unsigned char cmd[12]; |
| 1837 | int use_10_for_ms; | 1916 | int use_10_for_ms; |
| 1838 | int header_length; | 1917 | int header_length; |
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index f2193cd0d31f..895d212864cd 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h | |||
| @@ -261,6 +261,11 @@ extern int scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, | |||
| 261 | unsigned char *buffer, int len, int timeout, | 261 | unsigned char *buffer, int len, int timeout, |
| 262 | int retries, struct scsi_mode_data *data, | 262 | int retries, struct scsi_mode_data *data, |
| 263 | struct scsi_sense_hdr *); | 263 | struct scsi_sense_hdr *); |
| 264 | extern int scsi_mode_select(struct scsi_device *sdev, int pf, int sp, | ||
| 265 | int modepage, unsigned char *buffer, int len, | ||
| 266 | int timeout, int retries, | ||
| 267 | struct scsi_mode_data *data, | ||
| 268 | struct scsi_sense_hdr *); | ||
| 264 | extern int scsi_test_unit_ready(struct scsi_device *sdev, int timeout, | 269 | extern int scsi_test_unit_ready(struct scsi_device *sdev, int timeout, |
| 265 | int retries); | 270 | int retries); |
| 266 | extern int scsi_device_set_state(struct scsi_device *sdev, | 271 | extern int scsi_device_set_state(struct scsi_device *sdev, |
