diff options
author | Christoph Hellwig <hch@lst.de> | 2006-03-22 11:52:04 -0500 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2006-04-13 11:13:15 -0400 |
commit | 21b2f0c803adaf00fce1b606c50b49ae8b106773 (patch) | |
tree | 1acc834df309041ed0c5681f4bd222fd3e113900 /drivers/scsi | |
parent | 765fcab23d0a79ed7aab8da79766f5873d936f1b (diff) |
[SCSI] unify SCSI_IOCTL_SEND_COMMAND implementations
We currently have two implementations of this obsolete ioctl, one in
the block layer and one in the scsi code. Both of them have drawbacks.
This patch kills the scsi layer version after updating the block version
with the missing bits:
- argument checking
- use scatterlist I/O
- set number of retries based on the submitted command
This is the last user of non-S/G I/O except for the gdth driver, so
getting this in ASAP and through the scsi tree would be nie to kill
the non-S/G I/O path. Jens, what do you think about adding a check
for non-S/G I/O in the midlayer?
Thanks to Or Gerlitz for testing this patch.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/scsi_ioctl.c | 176 | ||||
-rw-r--r-- | drivers/scsi/sg.c | 2 |
2 files changed, 2 insertions, 176 deletions
diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index 36e930066649..a89aff61d3d8 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c | |||
@@ -158,180 +158,6 @@ int scsi_set_medium_removal(struct scsi_device *sdev, char state) | |||
158 | EXPORT_SYMBOL(scsi_set_medium_removal); | 158 | EXPORT_SYMBOL(scsi_set_medium_removal); |
159 | 159 | ||
160 | /* | 160 | /* |
161 | * This interface is deprecated - users should use the scsi generic (sg) | ||
162 | * interface instead, as this is a more flexible approach to performing | ||
163 | * generic SCSI commands on a device. | ||
164 | * | ||
165 | * The structure that we are passed should look like: | ||
166 | * | ||
167 | * struct sdata { | ||
168 | * unsigned int inlen; [i] Length of data to be written to device | ||
169 | * unsigned int outlen; [i] Length of data to be read from device | ||
170 | * unsigned char cmd[x]; [i] SCSI command (6 <= x <= 12). | ||
171 | * [o] Data read from device starts here. | ||
172 | * [o] On error, sense buffer starts here. | ||
173 | * unsigned char wdata[y]; [i] Data written to device starts here. | ||
174 | * }; | ||
175 | * Notes: | ||
176 | * - The SCSI command length is determined by examining the 1st byte | ||
177 | * of the given command. There is no way to override this. | ||
178 | * - Data transfers are limited to PAGE_SIZE (4K on i386, 8K on alpha). | ||
179 | * - The length (x + y) must be at least OMAX_SB_LEN bytes long to | ||
180 | * accommodate the sense buffer when an error occurs. | ||
181 | * The sense buffer is truncated to OMAX_SB_LEN (16) bytes so that | ||
182 | * old code will not be surprised. | ||
183 | * - If a Unix error occurs (e.g. ENOMEM) then the user will receive | ||
184 | * a negative return and the Unix error code in 'errno'. | ||
185 | * If the SCSI command succeeds then 0 is returned. | ||
186 | * Positive numbers returned are the compacted SCSI error codes (4 | ||
187 | * bytes in one int) where the lowest byte is the SCSI status. | ||
188 | * See the drivers/scsi/scsi.h file for more information on this. | ||
189 | * | ||
190 | */ | ||
191 | #define OMAX_SB_LEN 16 /* Old sense buffer length */ | ||
192 | |||
193 | int scsi_ioctl_send_command(struct scsi_device *sdev, | ||
194 | struct scsi_ioctl_command __user *sic) | ||
195 | { | ||
196 | char *buf; | ||
197 | unsigned char cmd[MAX_COMMAND_SIZE]; | ||
198 | unsigned char sense[SCSI_SENSE_BUFFERSIZE]; | ||
199 | char __user *cmd_in; | ||
200 | unsigned char opcode; | ||
201 | unsigned int inlen, outlen, cmdlen; | ||
202 | unsigned int needed, buf_needed; | ||
203 | int timeout, retries, result; | ||
204 | int data_direction; | ||
205 | gfp_t gfp_mask = GFP_KERNEL; | ||
206 | |||
207 | if (!sic) | ||
208 | return -EINVAL; | ||
209 | |||
210 | if (sdev->host->unchecked_isa_dma) | ||
211 | gfp_mask |= GFP_DMA; | ||
212 | |||
213 | /* | ||
214 | * Verify that we can read at least this much. | ||
215 | */ | ||
216 | if (!access_ok(VERIFY_READ, sic, sizeof(Scsi_Ioctl_Command))) | ||
217 | return -EFAULT; | ||
218 | |||
219 | if(__get_user(inlen, &sic->inlen)) | ||
220 | return -EFAULT; | ||
221 | |||
222 | if(__get_user(outlen, &sic->outlen)) | ||
223 | return -EFAULT; | ||
224 | |||
225 | /* | ||
226 | * We do not transfer more than MAX_BUF with this interface. | ||
227 | * If the user needs to transfer more data than this, they | ||
228 | * should use scsi_generics (sg) instead. | ||
229 | */ | ||
230 | if (inlen > MAX_BUF) | ||
231 | return -EINVAL; | ||
232 | if (outlen > MAX_BUF) | ||
233 | return -EINVAL; | ||
234 | |||
235 | cmd_in = sic->data; | ||
236 | if(get_user(opcode, cmd_in)) | ||
237 | return -EFAULT; | ||
238 | |||
239 | needed = buf_needed = (inlen > outlen ? inlen : outlen); | ||
240 | if (buf_needed) { | ||
241 | buf_needed = (buf_needed + 511) & ~511; | ||
242 | if (buf_needed > MAX_BUF) | ||
243 | buf_needed = MAX_BUF; | ||
244 | buf = kzalloc(buf_needed, gfp_mask); | ||
245 | if (!buf) | ||
246 | return -ENOMEM; | ||
247 | if (inlen == 0) { | ||
248 | data_direction = DMA_FROM_DEVICE; | ||
249 | } else if (outlen == 0 ) { | ||
250 | data_direction = DMA_TO_DEVICE; | ||
251 | } else { | ||
252 | /* | ||
253 | * Can this ever happen? | ||
254 | */ | ||
255 | data_direction = DMA_BIDIRECTIONAL; | ||
256 | } | ||
257 | |||
258 | } else { | ||
259 | buf = NULL; | ||
260 | data_direction = DMA_NONE; | ||
261 | } | ||
262 | |||
263 | /* | ||
264 | * Obtain the command from the user's address space. | ||
265 | */ | ||
266 | cmdlen = COMMAND_SIZE(opcode); | ||
267 | |||
268 | result = -EFAULT; | ||
269 | |||
270 | if (!access_ok(VERIFY_READ, cmd_in, cmdlen + inlen)) | ||
271 | goto error; | ||
272 | |||
273 | if(__copy_from_user(cmd, cmd_in, cmdlen)) | ||
274 | goto error; | ||
275 | |||
276 | /* | ||
277 | * Obtain the data to be sent to the device (if any). | ||
278 | */ | ||
279 | |||
280 | if(inlen && copy_from_user(buf, cmd_in + cmdlen, inlen)) | ||
281 | goto error; | ||
282 | |||
283 | switch (opcode) { | ||
284 | case SEND_DIAGNOSTIC: | ||
285 | case FORMAT_UNIT: | ||
286 | timeout = FORMAT_UNIT_TIMEOUT; | ||
287 | retries = 1; | ||
288 | break; | ||
289 | case START_STOP: | ||
290 | timeout = START_STOP_TIMEOUT; | ||
291 | retries = NORMAL_RETRIES; | ||
292 | break; | ||
293 | case MOVE_MEDIUM: | ||
294 | timeout = MOVE_MEDIUM_TIMEOUT; | ||
295 | retries = NORMAL_RETRIES; | ||
296 | break; | ||
297 | case READ_ELEMENT_STATUS: | ||
298 | timeout = READ_ELEMENT_STATUS_TIMEOUT; | ||
299 | retries = NORMAL_RETRIES; | ||
300 | break; | ||
301 | case READ_DEFECT_DATA: | ||
302 | timeout = READ_DEFECT_DATA_TIMEOUT; | ||
303 | retries = 1; | ||
304 | break; | ||
305 | default: | ||
306 | timeout = IOCTL_NORMAL_TIMEOUT; | ||
307 | retries = NORMAL_RETRIES; | ||
308 | break; | ||
309 | } | ||
310 | |||
311 | result = scsi_execute(sdev, cmd, data_direction, buf, needed, | ||
312 | sense, timeout, retries, 0); | ||
313 | |||
314 | /* | ||
315 | * If there was an error condition, pass the info back to the user. | ||
316 | */ | ||
317 | if (result) { | ||
318 | int sb_len = sizeof(*sense); | ||
319 | |||
320 | sb_len = (sb_len > OMAX_SB_LEN) ? OMAX_SB_LEN : sb_len; | ||
321 | if (copy_to_user(cmd_in, sense, sb_len)) | ||
322 | result = -EFAULT; | ||
323 | } else { | ||
324 | if (outlen && copy_to_user(cmd_in, buf, outlen)) | ||
325 | result = -EFAULT; | ||
326 | } | ||
327 | |||
328 | error: | ||
329 | kfree(buf); | ||
330 | return result; | ||
331 | } | ||
332 | EXPORT_SYMBOL(scsi_ioctl_send_command); | ||
333 | |||
334 | /* | ||
335 | * The scsi_ioctl_get_pci() function places into arg the value | 161 | * The scsi_ioctl_get_pci() function places into arg the value |
336 | * pci_dev::slot_name (8 characters) for the PCI device (if any). | 162 | * pci_dev::slot_name (8 characters) for the PCI device (if any). |
337 | * Returns: 0 on success | 163 | * Returns: 0 on success |
@@ -409,7 +235,7 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) | |||
409 | case SCSI_IOCTL_SEND_COMMAND: | 235 | case SCSI_IOCTL_SEND_COMMAND: |
410 | if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) | 236 | if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) |
411 | return -EACCES; | 237 | return -EACCES; |
412 | return scsi_ioctl_send_command(sdev, arg); | 238 | return sg_scsi_ioctl(NULL, sdev->request_queue, NULL, arg); |
413 | case SCSI_IOCTL_DOORLOCK: | 239 | case SCSI_IOCTL_DOORLOCK: |
414 | return scsi_set_medium_removal(sdev, SCSI_REMOVAL_PREVENT); | 240 | return scsi_set_medium_removal(sdev, SCSI_REMOVAL_PREVENT); |
415 | case SCSI_IOCTL_DOORUNLOCK: | 241 | case SCSI_IOCTL_DOORUNLOCK: |
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 7405d0df95db..fcf9243dfa7d 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c | |||
@@ -1044,7 +1044,7 @@ sg_ioctl(struct inode *inode, struct file *filp, | |||
1044 | if (!sg_allow_access(opcode, sdp->device->type)) | 1044 | if (!sg_allow_access(opcode, sdp->device->type)) |
1045 | return -EPERM; | 1045 | return -EPERM; |
1046 | } | 1046 | } |
1047 | return scsi_ioctl_send_command(sdp->device, p); | 1047 | return sg_scsi_ioctl(filp, sdp->device->request_queue, NULL, p); |
1048 | case SG_SET_DEBUG: | 1048 | case SG_SET_DEBUG: |
1049 | result = get_user(val, ip); | 1049 | result = get_user(val, ip); |
1050 | if (result) | 1050 | if (result) |