aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2006-03-22 11:52:04 -0500
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2006-04-13 11:13:15 -0400
commit21b2f0c803adaf00fce1b606c50b49ae8b106773 (patch)
tree1acc834df309041ed0c5681f4bd222fd3e113900 /drivers
parent765fcab23d0a79ed7aab8da79766f5873d936f1b (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')
-rw-r--r--drivers/scsi/scsi_ioctl.c176
-rw-r--r--drivers/scsi/sg.c2
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)
158EXPORT_SYMBOL(scsi_set_medium_removal); 158EXPORT_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
193int 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
328error:
329 kfree(buf);
330 return result;
331}
332EXPORT_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)