OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [drivers/] [scsi/] [scsi_ioctl.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1626 jcastillo
/*
2
 * Don't import our own symbols, as this would severely mess up our
3
 * symbol tables.
4
 */
5
#define _SCSI_SYMS_VER_
6
#define __NO_VERSION__
7
#include <linux/module.h>
8
 
9
#include <asm/io.h>
10
#include <asm/segment.h>
11
#include <asm/system.h>
12
#include <asm/page.h>
13
 
14
#include <linux/errno.h>
15
#include <linux/kernel.h>
16
#include <linux/sched.h>
17
#include <linux/mm.h>
18
#include <linux/string.h>
19
 
20
#include <linux/blk.h>
21
#include "scsi.h"
22
#include "hosts.h"
23
#include <scsi/scsi_ioctl.h>
24
 
25
#define NORMAL_RETRIES 5   
26
#define NORMAL_TIMEOUT (10 * HZ)
27
#define FORMAT_UNIT_TIMEOUT (2 * 60 * 60 * HZ)
28
#define START_STOP_TIMEOUT (60 * HZ)
29
#define MOVE_MEDIUM_TIMEOUT (5 * 60 * HZ)
30
#define READ_ELEMENT_STATUS_TIMEOUT (5 * 60 * HZ)
31
 
32
#define MAX_BUF PAGE_SIZE
33
 
34
#define max(a,b) (((a) > (b)) ? (a) : (b))
35
 
36
/*
37
 * If we are told to probe a host, we will return 0 if  the host is not
38
 * present, 1 if the host is present, and will return an identifying
39
 * string at *arg, if arg is non null, filling to the length stored at
40
 * (int *) arg
41
 */
42
 
43
static int ioctl_probe(struct Scsi_Host * host, void *buffer)
44
{
45
    int temp, result;
46
    unsigned int len,slen;
47
    const char * string;
48
 
49
    if ((temp = host->hostt->present) && buffer) {
50
        result = verify_area(VERIFY_READ, buffer, sizeof(long));
51
        if (result) return result;
52
 
53
        len = get_user ((unsigned int *) buffer);
54
        if(host->hostt->info)
55
            string = host->hostt->info(host);
56
        else
57
            string = host->hostt->name;
58
        if(string) {
59
            slen = strlen(string);
60
            if (len > slen)
61
                len = slen + 1;
62
            result = verify_area(VERIFY_WRITE, buffer, len);
63
            if (result) return result;
64
 
65
            memcpy_tofs (buffer, string, len);
66
        }
67
    }
68
    return temp;
69
}
70
 
71
/*
72
 *
73
 * The SCSI_IOCTL_SEND_COMMAND ioctl sends a command out to the SCSI host.
74
 * The NORMAL_TIMEOUT and NORMAL_RETRIES  variables are used.
75
 *
76
 * dev is the SCSI device struct ptr, *(int *) arg is the length of the
77
 * input data, if any, not including the command string & counts,
78
 * *((int *)arg + 1) is the output buffer size in bytes.
79
 *
80
 * *(char *) ((int *) arg)[2] the actual command byte.
81
 *
82
 * Note that if more than MAX_BUF bytes are requested to be transfered,
83
 * the ioctl will fail with error EINVAL.  MAX_BUF can be increased in
84
 * the future by increasing the size that scsi_malloc will accept.
85
 *
86
 * This size *does not* include the initial lengths that were passed.
87
 *
88
 * The SCSI command is read from the memory location immediately after the
89
 * length words, and the input data is right after the command.  The SCSI
90
 * routines know the command size based on the opcode decode.
91
 *
92
 * The output area is then filled in starting from the command byte.
93
 */
94
 
95
static void scsi_ioctl_done (Scsi_Cmnd * SCpnt)
96
{
97
    struct request * req;
98
 
99
    req = &SCpnt->request;
100
    req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */
101
 
102
    if (req->sem != NULL) {
103
        up(req->sem);
104
    }
105
}
106
 
107
static int ioctl_internal_command(Scsi_Device *dev, char * cmd,
108
                                  int timeout, int retries)
109
{
110
    int result;
111
    Scsi_Cmnd * SCpnt;
112
 
113
    SCpnt = allocate_device(NULL, dev, 1);
114
    {
115
        struct semaphore sem = MUTEX_LOCKED;
116
        SCpnt->request.sem = &sem;
117
        scsi_do_cmd(SCpnt,  cmd, NULL,  0, scsi_ioctl_done,  timeout, retries);
118
        down(&sem);
119
    }
120
 
121
    if(driver_byte(SCpnt->result) != 0)
122
        switch(SCpnt->sense_buffer[2] & 0xf) {
123
        case ILLEGAL_REQUEST:
124
            if(cmd[0] == ALLOW_MEDIUM_REMOVAL) dev->lockable = 0;
125
            else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n");
126
            break;
127
        case NOT_READY: /* This happens if there is no disc in drive */
128
            if(dev->removable){
129
                printk(KERN_INFO "Device not ready.  Make sure there is a disc in the drive.\n");
130
                break;
131
            };
132
        case UNIT_ATTENTION:
133
            if (dev->removable){
134
                dev->changed = 1;
135
                SCpnt->result = 0; /* This is no longer considered an error */
136
                printk(KERN_INFO "Disc change detected.\n");
137
                break;
138
            };
139
        default: /* Fall through for non-removable media */
140
            printk("SCSI error: host %d id %d lun %d return code = %x\n",
141
                   dev->host->host_no,
142
                   dev->id,
143
                   dev->lun,
144
                   SCpnt->result);
145
            printk("\tSense class %x, sense error %x, extended sense %x\n",
146
                   sense_class(SCpnt->sense_buffer[0]),
147
                   sense_error(SCpnt->sense_buffer[0]),
148
                   SCpnt->sense_buffer[2] & 0xf);
149
 
150
        };
151
 
152
    result = SCpnt->result;
153
    SCpnt->request.rq_status = RQ_INACTIVE;
154
 
155
    if (!SCpnt->device->was_reset && SCpnt->device->scsi_request_fn)
156
        (*SCpnt->device->scsi_request_fn)();
157
 
158
    wake_up(&SCpnt->device->device_wait);
159
    return result;
160
}
161
 
162
/*
163
 * This interface is depreciated - users should use the scsi generics
164
 * interface instead, as this is a more flexible approach to performing
165
 * generic SCSI commands on a device.
166
 */
167
int scsi_ioctl_send_command(Scsi_Device *dev, void *buffer)
168
{
169
    char * buf;
170
    unsigned char cmd[12];
171
    char * cmd_in;
172
    Scsi_Cmnd * SCpnt;
173
    unsigned char opcode;
174
    int inlen, outlen, cmdlen;
175
    int needed, buf_needed;
176
    int timeout, retries, result;
177
 
178
    if (!buffer)
179
        return -EINVAL;
180
 
181
 
182
    /*
183
     * Verify that we can read at least this much.
184
     */
185
    result = verify_area(VERIFY_READ, buffer, 2*sizeof(long) + 1);
186
    if (result) return result;
187
 
188
    /*
189
     * The structure that we are passed should look like:
190
     *
191
     * struct sdata {
192
     *  unsigned int inlen;
193
     *  unsigned int outlen;
194
     *  unsigned char  cmd[];  # However many bytes are used for cmd.
195
     *  unsigned char  data[];
196
     * };
197
     */
198
    inlen = get_user((unsigned int *) buffer);
199
    outlen = get_user( ((unsigned int *) buffer) + 1);
200
 
201
    /*
202
     * We do not transfer more than MAX_BUF with this interface.
203
     * If the user needs to transfer more data than this, they
204
     * should use scsi_generics instead.
205
     */
206
    if( inlen > MAX_BUF )  return -EINVAL;
207
    if( outlen > MAX_BUF )  return -EINVAL;
208
 
209
    cmd_in = (char *) ( ((int *)buffer) + 2);
210
    opcode = get_user(cmd_in);
211
 
212
    needed = buf_needed = (inlen > outlen ? inlen : outlen);
213
    if(buf_needed){
214
        buf_needed = (buf_needed + 511) & ~511;
215
        if (buf_needed > MAX_BUF) buf_needed = MAX_BUF;
216
        buf = (char *) scsi_malloc(buf_needed);
217
        if (!buf) return -ENOMEM;
218
        memset(buf, 0, buf_needed);
219
    } else
220
        buf = NULL;
221
 
222
    /*
223
     * Obtain the command from the user's address space.
224
     */
225
    cmdlen = COMMAND_SIZE(opcode);
226
 
227
    result = verify_area(VERIFY_READ, cmd_in,
228
                         cmdlen + inlen > MAX_BUF ? MAX_BUF : inlen);
229
    if (result) return result;
230
 
231
    memcpy_fromfs ((void *) cmd,  cmd_in,  cmdlen);
232
 
233
    /*
234
     * Obtain the data to be sent to the device (if any).
235
     */
236
    memcpy_fromfs ((void *) buf,
237
                   (void *) (cmd_in + cmdlen),
238
                   inlen);
239
 
240
    /*
241
     * Set the lun field to the correct value.
242
     */
243
    cmd[1] = ( cmd[1] & 0x1f ) | (dev->lun << 5);
244
 
245
    switch (opcode)
246
      {
247
      case FORMAT_UNIT:
248
        timeout = FORMAT_UNIT_TIMEOUT;
249
        retries = 1;
250
        break;
251
      case START_STOP:
252
        timeout = START_STOP_TIMEOUT;
253
        retries = NORMAL_RETRIES;
254
        break;
255
      case MOVE_MEDIUM:
256
        timeout = MOVE_MEDIUM_TIMEOUT;
257
        retries = NORMAL_RETRIES;
258
        break;
259
      case READ_ELEMENT_STATUS:
260
        timeout = READ_ELEMENT_STATUS_TIMEOUT;
261
        retries = NORMAL_RETRIES;
262
        break;
263
      default:
264
        timeout = NORMAL_TIMEOUT;
265
        retries = NORMAL_RETRIES;
266
        break;
267
      }
268
 
269
#ifndef DEBUG_NO_CMD
270
 
271
    SCpnt = allocate_device(NULL, dev, 1);
272
 
273
    {
274
        struct semaphore sem = MUTEX_LOCKED;
275
        SCpnt->request.sem = &sem;
276
        scsi_do_cmd(SCpnt,  cmd,  buf, needed,  scsi_ioctl_done,
277
                    timeout, retries);
278
        down(&sem);
279
    }
280
 
281
    /*
282
     * If there was an error condition, pass the info back to the user.
283
     */
284
    if(SCpnt->result) {
285
        result = verify_area(VERIFY_WRITE,
286
                             cmd_in,
287
                             sizeof(SCpnt->sense_buffer));
288
        if (result) return result;
289
        memcpy_tofs((void *) cmd_in,
290
                    SCpnt->sense_buffer,
291
                    sizeof(SCpnt->sense_buffer));
292
    } else {
293
        result = verify_area(VERIFY_WRITE, cmd_in, outlen);
294
        if (result) return result;
295
        memcpy_tofs ((void *) cmd_in,  buf,  outlen);
296
    }
297
    result = SCpnt->result;
298
 
299
    SCpnt->request.rq_status = RQ_INACTIVE;
300
 
301
    if (buf) scsi_free(buf, buf_needed);
302
 
303
    if(SCpnt->device->scsi_request_fn)
304
        (*SCpnt->device->scsi_request_fn)();
305
 
306
    wake_up(&SCpnt->device->device_wait);
307
    return result;
308
#else
309
    {
310
        int i;
311
        printk("scsi_ioctl : device %d.  command = ", dev->id);
312
        for (i = 0; i < 12; ++i)
313
            printk("%02x ", cmd[i]);
314
        printk("\nbuffer =");
315
        for (i = 0; i < 20; ++i)
316
            printk("%02x ", buf[i]);
317
        printk("\n");
318
        printk("inlen = %d, outlen = %d, cmdlen = %d\n",
319
               inlen, outlen, cmdlen);
320
        printk("buffer = %d, cmd_in = %d\n", buffer, cmd_in);
321
    }
322
    return 0;
323
#endif
324
}
325
 
326
/*
327
 * the scsi_ioctl() function differs from most ioctls in that it does
328
 * not take a major/minor number as the dev field.  Rather, it takes
329
 * a pointer to a scsi_devices[] element, a structure.
330
 */
331
int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
332
{
333
    int result;
334
    char scsi_cmd[12];
335
 
336
    /* No idea how this happens.... */
337
    if (!dev) return -ENXIO;
338
 
339
    switch (cmd) {
340
    case SCSI_IOCTL_GET_IDLUN:
341
        result = verify_area(VERIFY_WRITE, (void *) arg, 2*sizeof(long));
342
        if (result) return result;
343
 
344
        put_user(dev->id
345
                 + (dev->lun << 8)
346
                 + (dev->channel << 16)
347
                 + ((dev->host->hostt->proc_dir->low_ino & 0xff) << 24),
348
                    (unsigned long *) arg);
349
        put_user( dev->host->unique_id, (unsigned long *) arg+1);
350
        return 0;
351
    case SCSI_IOCTL_GET_BUS_NUMBER:
352
        result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
353
        if (result) return result;
354
        put_user( dev->host->host_no, (int *) arg);
355
        return 0;
356
    case SCSI_IOCTL_TAGGED_ENABLE:
357
        if(!suser())  return -EACCES;
358
        if(!dev->tagged_supported) return -EINVAL;
359
        dev->tagged_queue = 1;
360
        dev->current_tag = 1;
361
        return 0;
362
    case SCSI_IOCTL_TAGGED_DISABLE:
363
        if(!suser())  return -EACCES;
364
        if(!dev->tagged_supported) return -EINVAL;
365
        dev->tagged_queue = 0;
366
        dev->current_tag = 0;
367
        return 0;
368
    case SCSI_IOCTL_PROBE_HOST:
369
        return ioctl_probe(dev->host, arg);
370
    case SCSI_IOCTL_SEND_COMMAND:
371
        if(!suser() || securelevel > 0)  return -EACCES;
372
        return scsi_ioctl_send_command((Scsi_Device *) dev, arg);
373
    case SCSI_IOCTL_DOORLOCK:
374
        if (!dev->removable || !dev->lockable) return 0;
375
        scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
376
        scsi_cmd[1] = dev->lun << 5;
377
        scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
378
        scsi_cmd[4] = SCSI_REMOVAL_PREVENT;
379
        return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
380
                                      NORMAL_TIMEOUT, NORMAL_RETRIES);
381
        break;
382
    case SCSI_IOCTL_DOORUNLOCK:
383
        if (!dev->removable || !dev->lockable) return 0;
384
        scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
385
        scsi_cmd[1] = dev->lun << 5;
386
        scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
387
        scsi_cmd[4] = SCSI_REMOVAL_ALLOW;
388
        return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
389
                                      NORMAL_TIMEOUT, NORMAL_RETRIES);
390
    case SCSI_IOCTL_TEST_UNIT_READY:
391
        scsi_cmd[0] = TEST_UNIT_READY;
392
        scsi_cmd[1] = dev->lun << 5;
393
        scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
394
        scsi_cmd[4] = 0;
395
        return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
396
                                      NORMAL_TIMEOUT, NORMAL_RETRIES);
397
        break;
398
    case SCSI_IOCTL_START_UNIT:
399
        scsi_cmd[0] = START_STOP;
400
        scsi_cmd[1] = dev->lun << 5;
401
        scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
402
        scsi_cmd[4] = 1;
403
        return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
404
                                      START_STOP_TIMEOUT, NORMAL_RETRIES);
405
        break;
406
    case SCSI_IOCTL_STOP_UNIT:
407
        scsi_cmd[0] = START_STOP;
408
        scsi_cmd[1] = dev->lun << 5;
409
        scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
410
        scsi_cmd[4] = 0;
411
        return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd,
412
                                      START_STOP_TIMEOUT, NORMAL_RETRIES);
413
        break;
414
    default :
415
        return -EINVAL;
416
    }
417
    return -EINVAL;
418
}
419
 
420
/*
421
 * Just like scsi_ioctl, only callable from kernel space with no
422
 * fs segment fiddling.
423
 */
424
 
425
int kernel_scsi_ioctl (Scsi_Device *dev, int cmd, void *arg) {
426
    unsigned long oldfs;
427
    int tmp;
428
    oldfs = get_fs();
429
    set_fs(get_ds());
430
    tmp = scsi_ioctl (dev, cmd, arg);
431
    set_fs(oldfs);
432
    return tmp;
433
}
434
 
435
/*
436
 * Overrides for Emacs so that we almost follow Linus's tabbing style.
437
 * Emacs will notice this stuff at the end of the file and automatically
438
 * adjust the settings for this buffer only.  This must remain at the end
439
 * of the file.
440
 * ---------------------------------------------------------------------------
441
 * Local variables:
442
 * c-indent-level: 4
443
 * c-brace-imaginary-offset: 0
444
 * c-brace-offset: -4
445
 * c-argdecl-indent: 4
446
 * c-label-offset: -4
447
 * c-continued-statement-offset: 4
448
 * c-continued-brace-offset: 0
449
 * indent-tabs-mode: nil
450
 * tab-width: 8
451
 * End:
452
 */

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.