diff options
Diffstat (limited to 'drivers/scsi/scsi_lib.c')
-rw-r--r-- | drivers/scsi/scsi_lib.c | 157 |
1 files changed, 93 insertions, 64 deletions
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 701a328f7beb..ede158d08d9d 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c | |||
@@ -286,13 +286,12 @@ int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd, | |||
286 | int result; | 286 | int result; |
287 | 287 | ||
288 | if (sshdr) { | 288 | if (sshdr) { |
289 | sense = kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_NOIO); | 289 | sense = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_NOIO); |
290 | if (!sense) | 290 | if (!sense) |
291 | return DRIVER_ERROR << 24; | 291 | return DRIVER_ERROR << 24; |
292 | memset(sense, 0, SCSI_SENSE_BUFFERSIZE); | ||
293 | } | 292 | } |
294 | result = scsi_execute(sdev, cmd, data_direction, buffer, bufflen, | 293 | result = scsi_execute(sdev, cmd, data_direction, buffer, bufflen, |
295 | sense, timeout, retries, 0); | 294 | sense, timeout, retries, 0); |
296 | if (sshdr) | 295 | if (sshdr) |
297 | scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, sshdr); | 296 | scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, sshdr); |
298 | 297 | ||
@@ -1812,6 +1811,84 @@ void scsi_exit_queue(void) | |||
1812 | kmem_cache_destroy(sgp->slab); | 1811 | kmem_cache_destroy(sgp->slab); |
1813 | } | 1812 | } |
1814 | } | 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 | |||
1815 | /** | 1892 | /** |
1816 | * 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 |
1817 | * six bytes if necessary. | 1894 | * six bytes if necessary. |
@@ -1833,7 +1910,8 @@ void scsi_exit_queue(void) | |||
1833 | int | 1910 | int |
1834 | scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, | 1911 | scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, |
1835 | unsigned char *buffer, int len, int timeout, int retries, | 1912 | unsigned char *buffer, int len, int timeout, int retries, |
1836 | struct scsi_mode_data *data, struct scsi_sense_hdr *sshdr) { | 1913 | struct scsi_mode_data *data, struct scsi_sense_hdr *sshdr) |
1914 | { | ||
1837 | unsigned char cmd[12]; | 1915 | unsigned char cmd[12]; |
1838 | int use_10_for_ms; | 1916 | int use_10_for_ms; |
1839 | int header_length; | 1917 | int header_length; |
@@ -1893,8 +1971,16 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, | |||
1893 | } | 1971 | } |
1894 | 1972 | ||
1895 | if(scsi_status_is_good(result)) { | 1973 | if(scsi_status_is_good(result)) { |
1896 | data->header_length = header_length; | 1974 | if (unlikely(buffer[0] == 0x86 && buffer[1] == 0x0b && |
1897 | if(use_10_for_ms) { | 1975 | (modepage == 6 || modepage == 8))) { |
1976 | /* Initio breakage? */ | ||
1977 | header_length = 0; | ||
1978 | data->length = 13; | ||
1979 | data->medium_type = 0; | ||
1980 | data->device_specific = 0; | ||
1981 | data->longlba = 0; | ||
1982 | data->block_descriptor_length = 0; | ||
1983 | } else if(use_10_for_ms) { | ||
1898 | data->length = buffer[0]*256 + buffer[1] + 2; | 1984 | data->length = buffer[0]*256 + buffer[1] + 2; |
1899 | data->medium_type = buffer[2]; | 1985 | data->medium_type = buffer[2]; |
1900 | data->device_specific = buffer[3]; | 1986 | data->device_specific = buffer[3]; |
@@ -1907,6 +1993,7 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, | |||
1907 | data->device_specific = buffer[2]; | 1993 | data->device_specific = buffer[2]; |
1908 | data->block_descriptor_length = buffer[3]; | 1994 | data->block_descriptor_length = buffer[3]; |
1909 | } | 1995 | } |
1996 | data->header_length = header_length; | ||
1910 | } | 1997 | } |
1911 | 1998 | ||
1912 | return result; | 1999 | return result; |
@@ -2249,61 +2336,3 @@ scsi_target_unblock(struct device *dev) | |||
2249 | device_for_each_child(dev, NULL, target_unblock); | 2336 | device_for_each_child(dev, NULL, target_unblock); |
2250 | } | 2337 | } |
2251 | EXPORT_SYMBOL_GPL(scsi_target_unblock); | 2338 | EXPORT_SYMBOL_GPL(scsi_target_unblock); |
2252 | |||
2253 | |||
2254 | struct work_queue_work { | ||
2255 | struct work_struct work; | ||
2256 | void (*fn)(void *); | ||
2257 | void *data; | ||
2258 | }; | ||
2259 | |||
2260 | static void execute_in_process_context_work(void *data) | ||
2261 | { | ||
2262 | void (*fn)(void *data); | ||
2263 | struct work_queue_work *wqw = data; | ||
2264 | |||
2265 | fn = wqw->fn; | ||
2266 | data = wqw->data; | ||
2267 | |||
2268 | kfree(wqw); | ||
2269 | |||
2270 | fn(data); | ||
2271 | } | ||
2272 | |||
2273 | /** | ||
2274 | * scsi_execute_in_process_context - reliably execute the routine with user context | ||
2275 | * @fn: the function to execute | ||
2276 | * @data: data to pass to the function | ||
2277 | * | ||
2278 | * Executes the function immediately if process context is available, | ||
2279 | * otherwise schedules the function for delayed execution. | ||
2280 | * | ||
2281 | * Returns: 0 - function was executed | ||
2282 | * 1 - function was scheduled for execution | ||
2283 | * <0 - error | ||
2284 | */ | ||
2285 | int scsi_execute_in_process_context(void (*fn)(void *data), void *data) | ||
2286 | { | ||
2287 | struct work_queue_work *wqw; | ||
2288 | |||
2289 | if (!in_interrupt()) { | ||
2290 | fn(data); | ||
2291 | return 0; | ||
2292 | } | ||
2293 | |||
2294 | wqw = kmalloc(sizeof(struct work_queue_work), GFP_ATOMIC); | ||
2295 | |||
2296 | if (unlikely(!wqw)) { | ||
2297 | printk(KERN_ERR "Failed to allocate memory\n"); | ||
2298 | WARN_ON(1); | ||
2299 | return -ENOMEM; | ||
2300 | } | ||
2301 | |||
2302 | INIT_WORK(&wqw->work, execute_in_process_context_work, wqw); | ||
2303 | wqw->fn = fn; | ||
2304 | wqw->data = data; | ||
2305 | schedule_work(&wqw->work); | ||
2306 | |||
2307 | return 1; | ||
2308 | } | ||
2309 | EXPORT_SYMBOL_GPL(scsi_execute_in_process_context); | ||