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, |