Merge branch 'fix' of git://git.kernel.org/pub/scm/linux/kernel/git/ycmiao/pxa-linux-2.6
[linux-2.6] / drivers / scsi / ch.c
1 /*
2  * SCSI Media Changer device driver for Linux 2.6
3  *
4  *     (c) 1996-2003 Gerd Knorr <kraxel@bytesex.org>
5  *
6  */
7
8 #define VERSION "0.25"
9
10 #include <linux/module.h>
11 #include <linux/init.h>
12 #include <linux/fs.h>
13 #include <linux/kernel.h>
14 #include <linux/mm.h>
15 #include <linux/major.h>
16 #include <linux/string.h>
17 #include <linux/errno.h>
18 #include <linux/interrupt.h>
19 #include <linux/blkdev.h>
20 #include <linux/completion.h>
21 #include <linux/compat.h>
22 #include <linux/chio.h>                 /* here are all the ioctls */
23 #include <linux/mutex.h>
24 #include <linux/idr.h>
25 #include <linux/smp_lock.h>
26
27 #include <scsi/scsi.h>
28 #include <scsi/scsi_cmnd.h>
29 #include <scsi/scsi_driver.h>
30 #include <scsi/scsi_ioctl.h>
31 #include <scsi/scsi_host.h>
32 #include <scsi/scsi_device.h>
33 #include <scsi/scsi_eh.h>
34 #include <scsi/scsi_dbg.h>
35
36 #define CH_DT_MAX       16
37 #define CH_TYPES        8
38 #define CH_MAX_DEVS     128
39
40 MODULE_DESCRIPTION("device driver for scsi media changer devices");
41 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org>");
42 MODULE_LICENSE("GPL");
43 MODULE_ALIAS_CHARDEV_MAJOR(SCSI_CHANGER_MAJOR);
44 MODULE_ALIAS_SCSI_DEVICE(TYPE_MEDIUM_CHANGER);
45
46 static int init = 1;
47 module_param(init, int, 0444);
48 MODULE_PARM_DESC(init, \
49     "initialize element status on driver load (default: on)");
50
51 static int timeout_move = 300;
52 module_param(timeout_move, int, 0644);
53 MODULE_PARM_DESC(timeout_move,"timeout for move commands "
54                  "(default: 300 seconds)");
55
56 static int timeout_init = 3600;
57 module_param(timeout_init, int, 0644);
58 MODULE_PARM_DESC(timeout_init,"timeout for INITIALIZE ELEMENT STATUS "
59                  "(default: 3600 seconds)");
60
61 static int verbose = 1;
62 module_param(verbose, int, 0644);
63 MODULE_PARM_DESC(verbose,"be verbose (default: on)");
64
65 static int debug = 0;
66 module_param(debug, int, 0644);
67 MODULE_PARM_DESC(debug,"enable/disable debug messages, also prints more "
68                  "detailed sense codes on scsi errors (default: off)");
69
70 static int dt_id[CH_DT_MAX] = { [ 0 ... (CH_DT_MAX-1) ] = -1 };
71 static int dt_lun[CH_DT_MAX];
72 module_param_array(dt_id,  int, NULL, 0444);
73 module_param_array(dt_lun, int, NULL, 0444);
74
75 /* tell the driver about vendor-specific slots */
76 static int vendor_firsts[CH_TYPES-4];
77 static int vendor_counts[CH_TYPES-4];
78 module_param_array(vendor_firsts, int, NULL, 0444);
79 module_param_array(vendor_counts, int, NULL, 0444);
80
81 static const char * vendor_labels[CH_TYPES-4] = {
82         "v0", "v1", "v2", "v3"
83 };
84 // module_param_string_array(vendor_labels, NULL, 0444);
85
86 #define dprintk(fmt, arg...)    if (debug) \
87         printk(KERN_DEBUG "%s: " fmt, ch->name , ## arg)
88 #define vprintk(fmt, arg...)    if (verbose) \
89         printk(KERN_INFO "%s: " fmt, ch->name , ## arg)
90
91 /* ------------------------------------------------------------------- */
92
93 #define MAX_RETRIES   1
94
95 static struct class * ch_sysfs_class;
96
97 typedef struct {
98         struct list_head    list;
99         int                 minor;
100         char                name[8];
101         struct scsi_device  *device;
102         struct scsi_device  **dt;        /* ptrs to data transfer elements */
103         u_int               firsts[CH_TYPES];
104         u_int               counts[CH_TYPES];
105         u_int               unit_attention;
106         u_int               voltags;
107         struct mutex        lock;
108 } scsi_changer;
109
110 static DEFINE_IDR(ch_index_idr);
111 static DEFINE_SPINLOCK(ch_index_lock);
112
113 static const struct {
114         unsigned char  sense;
115         unsigned char  asc;
116         unsigned char  ascq;
117         int            errno;
118 } ch_err[] = {
119 /* Just filled in what looks right. Hav'nt checked any standard paper for
120    these errno assignments, so they may be wrong... */
121         {
122                 .sense  = ILLEGAL_REQUEST,
123                 .asc    = 0x21,
124                 .ascq   = 0x01,
125                 .errno  = EBADSLT, /* Invalid element address */
126         },{
127                 .sense  = ILLEGAL_REQUEST,
128                 .asc    = 0x28,
129                 .ascq   = 0x01,
130                 .errno  = EBADE,   /* Import or export element accessed */
131         },{
132                 .sense  = ILLEGAL_REQUEST,
133                 .asc    = 0x3B,
134                 .ascq   = 0x0D,
135                 .errno  = EXFULL,  /* Medium destination element full */
136         },{
137                 .sense  = ILLEGAL_REQUEST,
138                 .asc    = 0x3B,
139                 .ascq   = 0x0E,
140                 .errno  = EBADE,   /* Medium source element empty */
141         },{
142                 .sense  = ILLEGAL_REQUEST,
143                 .asc    = 0x20,
144                 .ascq   = 0x00,
145                 .errno  = EBADRQC, /* Invalid command operation code */
146         },{
147                 /* end of list */
148         }
149 };
150
151 /* ------------------------------------------------------------------- */
152
153 static int ch_find_errno(struct scsi_sense_hdr *sshdr)
154 {
155         int i,errno = 0;
156
157         /* Check to see if additional sense information is available */
158         if (scsi_sense_valid(sshdr) &&
159             sshdr->asc != 0) {
160                 for (i = 0; ch_err[i].errno != 0; i++) {
161                         if (ch_err[i].sense == sshdr->sense_key &&
162                             ch_err[i].asc   == sshdr->asc &&
163                             ch_err[i].ascq  == sshdr->ascq) {
164                                 errno = -ch_err[i].errno;
165                                 break;
166                         }
167                 }
168         }
169         if (errno == 0)
170                 errno = -EIO;
171         return errno;
172 }
173
174 static int
175 ch_do_scsi(scsi_changer *ch, unsigned char *cmd,
176            void *buffer, unsigned buflength,
177            enum dma_data_direction direction)
178 {
179         int errno, retries = 0, timeout, result;
180         struct scsi_sense_hdr sshdr;
181
182         timeout = (cmd[0] == INITIALIZE_ELEMENT_STATUS)
183                 ? timeout_init : timeout_move;
184
185  retry:
186         errno = 0;
187         if (debug) {
188                 dprintk("command: ");
189                 __scsi_print_command(cmd);
190         }
191
192         result = scsi_execute_req(ch->device, cmd, direction, buffer,
193                                   buflength, &sshdr, timeout * HZ,
194                                   MAX_RETRIES, NULL);
195
196         dprintk("result: 0x%x\n",result);
197         if (driver_byte(result) & DRIVER_SENSE) {
198                 if (debug)
199                         scsi_print_sense_hdr(ch->name, &sshdr);
200                 errno = ch_find_errno(&sshdr);
201
202                 switch(sshdr.sense_key) {
203                 case UNIT_ATTENTION:
204                         ch->unit_attention = 1;
205                         if (retries++ < 3)
206                                 goto retry;
207                         break;
208                 }
209         }
210         return errno;
211 }
212
213 /* ------------------------------------------------------------------------ */
214
215 static int
216 ch_elem_to_typecode(scsi_changer *ch, u_int elem)
217 {
218         int i;
219
220         for (i = 0; i < CH_TYPES; i++) {
221                 if (elem >= ch->firsts[i]  &&
222                     elem <  ch->firsts[i] +
223                     ch->counts[i])
224                         return i+1;
225         }
226         return 0;
227 }
228
229 static int
230 ch_read_element_status(scsi_changer *ch, u_int elem, char *data)
231 {
232         u_char  cmd[12];
233         u_char  *buffer;
234         int     result;
235
236         buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
237         if(!buffer)
238                 return -ENOMEM;
239
240  retry:
241         memset(cmd,0,sizeof(cmd));
242         cmd[0] = READ_ELEMENT_STATUS;
243         cmd[1] = (ch->device->lun << 5) |
244                 (ch->voltags ? 0x10 : 0) |
245                 ch_elem_to_typecode(ch,elem);
246         cmd[2] = (elem >> 8) & 0xff;
247         cmd[3] = elem        & 0xff;
248         cmd[5] = 1;
249         cmd[9] = 255;
250         if (0 == (result = ch_do_scsi(ch, cmd, buffer, 256, DMA_FROM_DEVICE))) {
251                 if (((buffer[16] << 8) | buffer[17]) != elem) {
252                         dprintk("asked for element 0x%02x, got 0x%02x\n",
253                                 elem,(buffer[16] << 8) | buffer[17]);
254                         kfree(buffer);
255                         return -EIO;
256                 }
257                 memcpy(data,buffer+16,16);
258         } else {
259                 if (ch->voltags) {
260                         ch->voltags = 0;
261                         vprintk("device has no volume tag support\n");
262                         goto retry;
263                 }
264                 dprintk("READ ELEMENT STATUS for element 0x%x failed\n",elem);
265         }
266         kfree(buffer);
267         return result;
268 }
269
270 static int
271 ch_init_elem(scsi_changer *ch)
272 {
273         int err;
274         u_char cmd[6];
275
276         vprintk("INITIALIZE ELEMENT STATUS, may take some time ...\n");
277         memset(cmd,0,sizeof(cmd));
278         cmd[0] = INITIALIZE_ELEMENT_STATUS;
279         cmd[1] = ch->device->lun << 5;
280         err = ch_do_scsi(ch, cmd, NULL, 0, DMA_NONE);
281         vprintk("... finished\n");
282         return err;
283 }
284
285 static int
286 ch_readconfig(scsi_changer *ch)
287 {
288         u_char  cmd[10], data[16];
289         u_char  *buffer;
290         int     result,id,lun,i;
291         u_int   elem;
292
293         buffer = kzalloc(512, GFP_KERNEL | GFP_DMA);
294         if (!buffer)
295                 return -ENOMEM;
296
297         memset(cmd,0,sizeof(cmd));
298         cmd[0] = MODE_SENSE;
299         cmd[1] = ch->device->lun << 5;
300         cmd[2] = 0x1d;
301         cmd[4] = 255;
302         result = ch_do_scsi(ch, cmd, buffer, 255, DMA_FROM_DEVICE);
303         if (0 != result) {
304                 cmd[1] |= (1<<3);
305                 result  = ch_do_scsi(ch, cmd, buffer, 255, DMA_FROM_DEVICE);
306         }
307         if (0 == result) {
308                 ch->firsts[CHET_MT] =
309                         (buffer[buffer[3]+ 6] << 8) | buffer[buffer[3]+ 7];
310                 ch->counts[CHET_MT] =
311                         (buffer[buffer[3]+ 8] << 8) | buffer[buffer[3]+ 9];
312                 ch->firsts[CHET_ST] =
313                         (buffer[buffer[3]+10] << 8) | buffer[buffer[3]+11];
314                 ch->counts[CHET_ST] =
315                         (buffer[buffer[3]+12] << 8) | buffer[buffer[3]+13];
316                 ch->firsts[CHET_IE] =
317                         (buffer[buffer[3]+14] << 8) | buffer[buffer[3]+15];
318                 ch->counts[CHET_IE] =
319                         (buffer[buffer[3]+16] << 8) | buffer[buffer[3]+17];
320                 ch->firsts[CHET_DT] =
321                         (buffer[buffer[3]+18] << 8) | buffer[buffer[3]+19];
322                 ch->counts[CHET_DT] =
323                         (buffer[buffer[3]+20] << 8) | buffer[buffer[3]+21];
324                 vprintk("type #1 (mt): 0x%x+%d [medium transport]\n",
325                         ch->firsts[CHET_MT],
326                         ch->counts[CHET_MT]);
327                 vprintk("type #2 (st): 0x%x+%d [storage]\n",
328                         ch->firsts[CHET_ST],
329                         ch->counts[CHET_ST]);
330                 vprintk("type #3 (ie): 0x%x+%d [import/export]\n",
331                         ch->firsts[CHET_IE],
332                         ch->counts[CHET_IE]);
333                 vprintk("type #4 (dt): 0x%x+%d [data transfer]\n",
334                         ch->firsts[CHET_DT],
335                         ch->counts[CHET_DT]);
336         } else {
337                 vprintk("reading element address assigment page failed!\n");
338         }
339
340         /* vendor specific element types */
341         for (i = 0; i < 4; i++) {
342                 if (0 == vendor_counts[i])
343                         continue;
344                 if (NULL == vendor_labels[i])
345                         continue;
346                 ch->firsts[CHET_V1+i] = vendor_firsts[i];
347                 ch->counts[CHET_V1+i] = vendor_counts[i];
348                 vprintk("type #%d (v%d): 0x%x+%d [%s, vendor specific]\n",
349                         i+5,i+1,vendor_firsts[i],vendor_counts[i],
350                         vendor_labels[i]);
351         }
352
353         /* look up the devices of the data transfer elements */
354         ch->dt = kmalloc(ch->counts[CHET_DT]*sizeof(struct scsi_device),
355                          GFP_KERNEL);
356         for (elem = 0; elem < ch->counts[CHET_DT]; elem++) {
357                 id  = -1;
358                 lun = 0;
359                 if (elem < CH_DT_MAX  &&  -1 != dt_id[elem]) {
360                         id  = dt_id[elem];
361                         lun = dt_lun[elem];
362                         vprintk("dt 0x%x: [insmod option] ",
363                                 elem+ch->firsts[CHET_DT]);
364                 } else if (0 != ch_read_element_status
365                            (ch,elem+ch->firsts[CHET_DT],data)) {
366                         vprintk("dt 0x%x: READ ELEMENT STATUS failed\n",
367                                 elem+ch->firsts[CHET_DT]);
368                 } else {
369                         vprintk("dt 0x%x: ",elem+ch->firsts[CHET_DT]);
370                         if (data[6] & 0x80) {
371                                 if (verbose)
372                                         printk("not this SCSI bus\n");
373                                 ch->dt[elem] = NULL;
374                         } else if (0 == (data[6] & 0x30)) {
375                                 if (verbose)
376                                         printk("ID/LUN unknown\n");
377                                 ch->dt[elem] = NULL;
378                         } else {
379                                 id  = ch->device->id;
380                                 lun = 0;
381                                 if (data[6] & 0x20) id  = data[7];
382                                 if (data[6] & 0x10) lun = data[6] & 7;
383                         }
384                 }
385                 if (-1 != id) {
386                         if (verbose)
387                                 printk("ID %i, LUN %i, ",id,lun);
388                         ch->dt[elem] =
389                                 scsi_device_lookup(ch->device->host,
390                                                    ch->device->channel,
391                                                    id,lun);
392                         if (!ch->dt[elem]) {
393                                 /* should not happen */
394                                 if (verbose)
395                                         printk("Huh? device not found!\n");
396                         } else {
397                                 if (verbose)
398                                         printk("name: %8.8s %16.16s %4.4s\n",
399                                                ch->dt[elem]->vendor,
400                                                ch->dt[elem]->model,
401                                                ch->dt[elem]->rev);
402                         }
403                 }
404         }
405         ch->voltags = 1;
406         kfree(buffer);
407
408         return 0;
409 }
410
411 /* ------------------------------------------------------------------------ */
412
413 static int
414 ch_position(scsi_changer *ch, u_int trans, u_int elem, int rotate)
415 {
416         u_char  cmd[10];
417
418         dprintk("position: 0x%x\n",elem);
419         if (0 == trans)
420                 trans = ch->firsts[CHET_MT];
421         memset(cmd,0,sizeof(cmd));
422         cmd[0]  = POSITION_TO_ELEMENT;
423         cmd[1]  = ch->device->lun << 5;
424         cmd[2]  = (trans >> 8) & 0xff;
425         cmd[3]  =  trans       & 0xff;
426         cmd[4]  = (elem  >> 8) & 0xff;
427         cmd[5]  =  elem        & 0xff;
428         cmd[8]  = rotate ? 1 : 0;
429         return ch_do_scsi(ch, cmd, NULL, 0, DMA_NONE);
430 }
431
432 static int
433 ch_move(scsi_changer *ch, u_int trans, u_int src, u_int dest, int rotate)
434 {
435         u_char  cmd[12];
436
437         dprintk("move: 0x%x => 0x%x\n",src,dest);
438         if (0 == trans)
439                 trans = ch->firsts[CHET_MT];
440         memset(cmd,0,sizeof(cmd));
441         cmd[0]  = MOVE_MEDIUM;
442         cmd[1]  = ch->device->lun << 5;
443         cmd[2]  = (trans >> 8) & 0xff;
444         cmd[3]  =  trans       & 0xff;
445         cmd[4]  = (src   >> 8) & 0xff;
446         cmd[5]  =  src         & 0xff;
447         cmd[6]  = (dest  >> 8) & 0xff;
448         cmd[7]  =  dest        & 0xff;
449         cmd[10] = rotate ? 1 : 0;
450         return ch_do_scsi(ch, cmd, NULL,0, DMA_NONE);
451 }
452
453 static int
454 ch_exchange(scsi_changer *ch, u_int trans, u_int src,
455             u_int dest1, u_int dest2, int rotate1, int rotate2)
456 {
457         u_char  cmd[12];
458
459         dprintk("exchange: 0x%x => 0x%x => 0x%x\n",
460                 src,dest1,dest2);
461         if (0 == trans)
462                 trans = ch->firsts[CHET_MT];
463         memset(cmd,0,sizeof(cmd));
464         cmd[0]  = EXCHANGE_MEDIUM;
465         cmd[1]  = ch->device->lun << 5;
466         cmd[2]  = (trans >> 8) & 0xff;
467         cmd[3]  =  trans       & 0xff;
468         cmd[4]  = (src   >> 8) & 0xff;
469         cmd[5]  =  src         & 0xff;
470         cmd[6]  = (dest1 >> 8) & 0xff;
471         cmd[7]  =  dest1       & 0xff;
472         cmd[8]  = (dest2 >> 8) & 0xff;
473         cmd[9]  =  dest2       & 0xff;
474         cmd[10] = (rotate1 ? 1 : 0) | (rotate2 ? 2 : 0);
475
476         return ch_do_scsi(ch, cmd, NULL,0, DMA_NONE);
477 }
478
479 static void
480 ch_check_voltag(char *tag)
481 {
482         int i;
483
484         for (i = 0; i < 32; i++) {
485                 /* restrict to ascii */
486                 if (tag[i] >= 0x7f || tag[i] < 0x20)
487                         tag[i] = ' ';
488                 /* don't allow search wildcards */
489                 if (tag[i] == '?' ||
490                     tag[i] == '*')
491                         tag[i] = ' ';
492         }
493 }
494
495 static int
496 ch_set_voltag(scsi_changer *ch, u_int elem,
497               int alternate, int clear, u_char *tag)
498 {
499         u_char  cmd[12];
500         u_char  *buffer;
501         int result;
502
503         buffer = kzalloc(512, GFP_KERNEL);
504         if (!buffer)
505                 return -ENOMEM;
506
507         dprintk("%s %s voltag: 0x%x => \"%s\"\n",
508                 clear     ? "clear"     : "set",
509                 alternate ? "alternate" : "primary",
510                 elem, tag);
511         memset(cmd,0,sizeof(cmd));
512         cmd[0]  = SEND_VOLUME_TAG;
513         cmd[1] = (ch->device->lun << 5) |
514                 ch_elem_to_typecode(ch,elem);
515         cmd[2] = (elem >> 8) & 0xff;
516         cmd[3] = elem        & 0xff;
517         cmd[5] = clear
518                 ? (alternate ? 0x0d : 0x0c)
519                 : (alternate ? 0x0b : 0x0a);
520
521         cmd[9] = 255;
522
523         memcpy(buffer,tag,32);
524         ch_check_voltag(buffer);
525
526         result = ch_do_scsi(ch, cmd, buffer, 256, DMA_TO_DEVICE);
527         kfree(buffer);
528         return result;
529 }
530
531 static int ch_gstatus(scsi_changer *ch, int type, unsigned char __user *dest)
532 {
533         int retval = 0;
534         u_char data[16];
535         unsigned int i;
536
537         mutex_lock(&ch->lock);
538         for (i = 0; i < ch->counts[type]; i++) {
539                 if (0 != ch_read_element_status
540                     (ch, ch->firsts[type]+i,data)) {
541                         retval = -EIO;
542                         break;
543                 }
544                 put_user(data[2], dest+i);
545                 if (data[2] & CESTATUS_EXCEPT)
546                         vprintk("element 0x%x: asc=0x%x, ascq=0x%x\n",
547                                 ch->firsts[type]+i,
548                                 (int)data[4],(int)data[5]);
549                 retval = ch_read_element_status
550                         (ch, ch->firsts[type]+i,data);
551                 if (0 != retval)
552                         break;
553         }
554         mutex_unlock(&ch->lock);
555         return retval;
556 }
557
558 /* ------------------------------------------------------------------------ */
559
560 static int
561 ch_release(struct inode *inode, struct file *file)
562 {
563         scsi_changer *ch = file->private_data;
564
565         scsi_device_put(ch->device);
566         file->private_data = NULL;
567         return 0;
568 }
569
570 static int
571 ch_open(struct inode *inode, struct file *file)
572 {
573         scsi_changer *ch;
574         int minor = iminor(inode);
575
576         lock_kernel();
577         spin_lock(&ch_index_lock);
578         ch = idr_find(&ch_index_idr, minor);
579
580         if (NULL == ch || scsi_device_get(ch->device)) {
581                 spin_unlock(&ch_index_lock);
582                 unlock_kernel();
583                 return -ENXIO;
584         }
585         spin_unlock(&ch_index_lock);
586
587         file->private_data = ch;
588         unlock_kernel();
589         return 0;
590 }
591
592 static int
593 ch_checkrange(scsi_changer *ch, unsigned int type, unsigned int unit)
594 {
595         if (type >= CH_TYPES  ||  unit >= ch->counts[type])
596                 return -1;
597         return 0;
598 }
599
600 static long ch_ioctl(struct file *file,
601                     unsigned int cmd, unsigned long arg)
602 {
603         scsi_changer *ch = file->private_data;
604         int retval;
605         void __user *argp = (void __user *)arg;
606
607         switch (cmd) {
608         case CHIOGPARAMS:
609         {
610                 struct changer_params params;
611
612                 params.cp_curpicker = 0;
613                 params.cp_npickers  = ch->counts[CHET_MT];
614                 params.cp_nslots    = ch->counts[CHET_ST];
615                 params.cp_nportals  = ch->counts[CHET_IE];
616                 params.cp_ndrives   = ch->counts[CHET_DT];
617
618                 if (copy_to_user(argp, &params, sizeof(params)))
619                         return -EFAULT;
620                 return 0;
621         }
622         case CHIOGVPARAMS:
623         {
624                 struct changer_vendor_params vparams;
625
626                 memset(&vparams,0,sizeof(vparams));
627                 if (ch->counts[CHET_V1]) {
628                         vparams.cvp_n1  = ch->counts[CHET_V1];
629                         strncpy(vparams.cvp_label1,vendor_labels[0],16);
630                 }
631                 if (ch->counts[CHET_V2]) {
632                         vparams.cvp_n2  = ch->counts[CHET_V2];
633                         strncpy(vparams.cvp_label2,vendor_labels[1],16);
634                 }
635                 if (ch->counts[CHET_V3]) {
636                         vparams.cvp_n3  = ch->counts[CHET_V3];
637                         strncpy(vparams.cvp_label3,vendor_labels[2],16);
638                 }
639                 if (ch->counts[CHET_V4]) {
640                         vparams.cvp_n4  = ch->counts[CHET_V4];
641                         strncpy(vparams.cvp_label4,vendor_labels[3],16);
642                 }
643                 if (copy_to_user(argp, &vparams, sizeof(vparams)))
644                         return -EFAULT;
645                 return 0;
646         }
647
648         case CHIOPOSITION:
649         {
650                 struct changer_position pos;
651
652                 if (copy_from_user(&pos, argp, sizeof (pos)))
653                         return -EFAULT;
654
655                 if (0 != ch_checkrange(ch, pos.cp_type, pos.cp_unit)) {
656                         dprintk("CHIOPOSITION: invalid parameter\n");
657                         return -EBADSLT;
658                 }
659                 mutex_lock(&ch->lock);
660                 retval = ch_position(ch,0,
661                                      ch->firsts[pos.cp_type] + pos.cp_unit,
662                                      pos.cp_flags & CP_INVERT);
663                 mutex_unlock(&ch->lock);
664                 return retval;
665         }
666
667         case CHIOMOVE:
668         {
669                 struct changer_move mv;
670
671                 if (copy_from_user(&mv, argp, sizeof (mv)))
672                         return -EFAULT;
673
674                 if (0 != ch_checkrange(ch, mv.cm_fromtype, mv.cm_fromunit) ||
675                     0 != ch_checkrange(ch, mv.cm_totype,   mv.cm_tounit  )) {
676                         dprintk("CHIOMOVE: invalid parameter\n");
677                         return -EBADSLT;
678                 }
679
680                 mutex_lock(&ch->lock);
681                 retval = ch_move(ch,0,
682                                  ch->firsts[mv.cm_fromtype] + mv.cm_fromunit,
683                                  ch->firsts[mv.cm_totype]   + mv.cm_tounit,
684                                  mv.cm_flags & CM_INVERT);
685                 mutex_unlock(&ch->lock);
686                 return retval;
687         }
688
689         case CHIOEXCHANGE:
690         {
691                 struct changer_exchange mv;
692
693                 if (copy_from_user(&mv, argp, sizeof (mv)))
694                         return -EFAULT;
695
696                 if (0 != ch_checkrange(ch, mv.ce_srctype,  mv.ce_srcunit ) ||
697                     0 != ch_checkrange(ch, mv.ce_fdsttype, mv.ce_fdstunit) ||
698                     0 != ch_checkrange(ch, mv.ce_sdsttype, mv.ce_sdstunit)) {
699                         dprintk("CHIOEXCHANGE: invalid parameter\n");
700                         return -EBADSLT;
701                 }
702
703                 mutex_lock(&ch->lock);
704                 retval = ch_exchange
705                         (ch,0,
706                          ch->firsts[mv.ce_srctype]  + mv.ce_srcunit,
707                          ch->firsts[mv.ce_fdsttype] + mv.ce_fdstunit,
708                          ch->firsts[mv.ce_sdsttype] + mv.ce_sdstunit,
709                          mv.ce_flags & CE_INVERT1, mv.ce_flags & CE_INVERT2);
710                 mutex_unlock(&ch->lock);
711                 return retval;
712         }
713
714         case CHIOGSTATUS:
715         {
716                 struct changer_element_status ces;
717
718                 if (copy_from_user(&ces, argp, sizeof (ces)))
719                         return -EFAULT;
720                 if (ces.ces_type < 0 || ces.ces_type >= CH_TYPES)
721                         return -EINVAL;
722
723                 return ch_gstatus(ch, ces.ces_type, ces.ces_data);
724         }
725
726         case CHIOGELEM:
727         {
728                 struct changer_get_element cge;
729                 u_char ch_cmd[12];
730                 u_char *buffer;
731                 unsigned int elem;
732                 int     result,i;
733
734                 if (copy_from_user(&cge, argp, sizeof (cge)))
735                         return -EFAULT;
736
737                 if (0 != ch_checkrange(ch, cge.cge_type, cge.cge_unit))
738                         return -EINVAL;
739                 elem = ch->firsts[cge.cge_type] + cge.cge_unit;
740
741                 buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
742                 if (!buffer)
743                         return -ENOMEM;
744                 mutex_lock(&ch->lock);
745
746         voltag_retry:
747                 memset(ch_cmd, 0, sizeof(ch_cmd));
748                 ch_cmd[0] = READ_ELEMENT_STATUS;
749                 ch_cmd[1] = (ch->device->lun << 5) |
750                         (ch->voltags ? 0x10 : 0) |
751                         ch_elem_to_typecode(ch,elem);
752                 ch_cmd[2] = (elem >> 8) & 0xff;
753                 ch_cmd[3] = elem        & 0xff;
754                 ch_cmd[5] = 1;
755                 ch_cmd[9] = 255;
756
757                 result = ch_do_scsi(ch, ch_cmd, buffer, 256, DMA_FROM_DEVICE);
758                 if (!result) {
759                         cge.cge_status = buffer[18];
760                         cge.cge_flags = 0;
761                         if (buffer[18] & CESTATUS_EXCEPT) {
762                                 cge.cge_errno = EIO;
763                         }
764                         if (buffer[25] & 0x80) {
765                                 cge.cge_flags |= CGE_SRC;
766                                 if (buffer[25] & 0x40)
767                                         cge.cge_flags |= CGE_INVERT;
768                                 elem = (buffer[26]<<8) | buffer[27];
769                                 for (i = 0; i < 4; i++) {
770                                         if (elem >= ch->firsts[i] &&
771                                             elem <  ch->firsts[i] + ch->counts[i]) {
772                                                 cge.cge_srctype = i;
773                                                 cge.cge_srcunit = elem-ch->firsts[i];
774                                         }
775                                 }
776                         }
777                         if ((buffer[22] & 0x30) == 0x30) {
778                                 cge.cge_flags |= CGE_IDLUN;
779                                 cge.cge_id  = buffer[23];
780                                 cge.cge_lun = buffer[22] & 7;
781                         }
782                         if (buffer[9] & 0x80) {
783                                 cge.cge_flags |= CGE_PVOLTAG;
784                                 memcpy(cge.cge_pvoltag,buffer+28,36);
785                         }
786                         if (buffer[9] & 0x40) {
787                                 cge.cge_flags |= CGE_AVOLTAG;
788                                 memcpy(cge.cge_avoltag,buffer+64,36);
789                         }
790                 } else if (ch->voltags) {
791                         ch->voltags = 0;
792                         vprintk("device has no volume tag support\n");
793                         goto voltag_retry;
794                 }
795                 kfree(buffer);
796                 mutex_unlock(&ch->lock);
797
798                 if (copy_to_user(argp, &cge, sizeof (cge)))
799                         return -EFAULT;
800                 return result;
801         }
802
803         case CHIOINITELEM:
804         {
805                 mutex_lock(&ch->lock);
806                 retval = ch_init_elem(ch);
807                 mutex_unlock(&ch->lock);
808                 return retval;
809         }
810
811         case CHIOSVOLTAG:
812         {
813                 struct changer_set_voltag csv;
814                 int elem;
815
816                 if (copy_from_user(&csv, argp, sizeof(csv)))
817                         return -EFAULT;
818
819                 if (0 != ch_checkrange(ch, csv.csv_type, csv.csv_unit)) {
820                         dprintk("CHIOSVOLTAG: invalid parameter\n");
821                         return -EBADSLT;
822                 }
823                 elem = ch->firsts[csv.csv_type] + csv.csv_unit;
824                 mutex_lock(&ch->lock);
825                 retval = ch_set_voltag(ch, elem,
826                                        csv.csv_flags & CSV_AVOLTAG,
827                                        csv.csv_flags & CSV_CLEARTAG,
828                                        csv.csv_voltag);
829                 mutex_unlock(&ch->lock);
830                 return retval;
831         }
832
833         default:
834                 return scsi_ioctl(ch->device, cmd, argp);
835
836         }
837 }
838
839 #ifdef CONFIG_COMPAT
840
841 struct changer_element_status32 {
842         int             ces_type;
843         compat_uptr_t   ces_data;
844 };
845 #define CHIOGSTATUS32  _IOW('c', 8,struct changer_element_status32)
846
847 static long ch_ioctl_compat(struct file * file,
848                             unsigned int cmd, unsigned long arg)
849 {
850         scsi_changer *ch = file->private_data;
851
852         switch (cmd) {
853         case CHIOGPARAMS:
854         case CHIOGVPARAMS:
855         case CHIOPOSITION:
856         case CHIOMOVE:
857         case CHIOEXCHANGE:
858         case CHIOGELEM:
859         case CHIOINITELEM:
860         case CHIOSVOLTAG:
861                 /* compatible */
862                 return ch_ioctl(file, cmd, arg);
863         case CHIOGSTATUS32:
864         {
865                 struct changer_element_status32 ces32;
866                 unsigned char __user *data;
867
868                 if (copy_from_user(&ces32, (void __user *)arg, sizeof (ces32)))
869                         return -EFAULT;
870                 if (ces32.ces_type < 0 || ces32.ces_type >= CH_TYPES)
871                         return -EINVAL;
872
873                 data = compat_ptr(ces32.ces_data);
874                 return ch_gstatus(ch, ces32.ces_type, data);
875         }
876         default:
877                 // return scsi_ioctl_compat(ch->device, cmd, (void*)arg);
878                 return -ENOIOCTLCMD;
879
880         }
881 }
882 #endif
883
884 /* ------------------------------------------------------------------------ */
885
886 static int ch_probe(struct device *dev)
887 {
888         struct scsi_device *sd = to_scsi_device(dev);
889         struct device *class_dev;
890         int minor, ret = -ENOMEM;
891         scsi_changer *ch;
892
893         if (sd->type != TYPE_MEDIUM_CHANGER)
894                 return -ENODEV;
895
896         ch = kzalloc(sizeof(*ch), GFP_KERNEL);
897         if (NULL == ch)
898                 return -ENOMEM;
899
900         if (!idr_pre_get(&ch_index_idr, GFP_KERNEL))
901                 goto free_ch;
902
903         spin_lock(&ch_index_lock);
904         ret = idr_get_new(&ch_index_idr, ch, &minor);
905         spin_unlock(&ch_index_lock);
906
907         if (ret)
908                 goto free_ch;
909
910         if (minor > CH_MAX_DEVS) {
911                 ret = -ENODEV;
912                 goto remove_idr;
913         }
914
915         ch->minor = minor;
916         sprintf(ch->name,"ch%d",ch->minor);
917
918         class_dev = device_create(ch_sysfs_class, dev,
919                                   MKDEV(SCSI_CHANGER_MAJOR, ch->minor), ch,
920                                   "s%s", ch->name);
921         if (IS_ERR(class_dev)) {
922                 printk(KERN_WARNING "ch%d: device_create failed\n",
923                        ch->minor);
924                 ret = PTR_ERR(class_dev);
925                 goto remove_idr;
926         }
927
928         mutex_init(&ch->lock);
929         ch->device = sd;
930         ch_readconfig(ch);
931         if (init)
932                 ch_init_elem(ch);
933
934         dev_set_drvdata(dev, ch);
935         sdev_printk(KERN_INFO, sd, "Attached scsi changer %s\n", ch->name);
936
937         return 0;
938 remove_idr:
939         idr_remove(&ch_index_idr, minor);
940 free_ch:
941         kfree(ch);
942         return ret;
943 }
944
945 static int ch_remove(struct device *dev)
946 {
947         scsi_changer *ch = dev_get_drvdata(dev);
948
949         spin_lock(&ch_index_lock);
950         idr_remove(&ch_index_idr, ch->minor);
951         spin_unlock(&ch_index_lock);
952
953         device_destroy(ch_sysfs_class, MKDEV(SCSI_CHANGER_MAJOR,ch->minor));
954         kfree(ch->dt);
955         kfree(ch);
956         return 0;
957 }
958
959 static struct scsi_driver ch_template = {
960         .owner          = THIS_MODULE,
961         .gendrv         = {
962                 .name   = "ch",
963                 .probe  = ch_probe,
964                 .remove = ch_remove,
965         },
966 };
967
968 static const struct file_operations changer_fops = {
969         .owner          = THIS_MODULE,
970         .open           = ch_open,
971         .release        = ch_release,
972         .unlocked_ioctl = ch_ioctl,
973 #ifdef CONFIG_COMPAT
974         .compat_ioctl   = ch_ioctl_compat,
975 #endif
976 };
977
978 static int __init init_ch_module(void)
979 {
980         int rc;
981
982         printk(KERN_INFO "SCSI Media Changer driver v" VERSION " \n");
983         ch_sysfs_class = class_create(THIS_MODULE, "scsi_changer");
984         if (IS_ERR(ch_sysfs_class)) {
985                 rc = PTR_ERR(ch_sysfs_class);
986                 return rc;
987         }
988         rc = register_chrdev(SCSI_CHANGER_MAJOR,"ch",&changer_fops);
989         if (rc < 0) {
990                 printk("Unable to get major %d for SCSI-Changer\n",
991                        SCSI_CHANGER_MAJOR);
992                 goto fail1;
993         }
994         rc = scsi_register_driver(&ch_template.gendrv);
995         if (rc < 0)
996                 goto fail2;
997         return 0;
998
999  fail2:
1000         unregister_chrdev(SCSI_CHANGER_MAJOR, "ch");
1001  fail1:
1002         class_destroy(ch_sysfs_class);
1003         return rc;
1004 }
1005
1006 static void __exit exit_ch_module(void)
1007 {
1008         scsi_unregister_driver(&ch_template.gendrv);
1009         unregister_chrdev(SCSI_CHANGER_MAJOR, "ch");
1010         class_destroy(ch_sysfs_class);
1011         idr_destroy(&ch_index_idr);
1012 }
1013
1014 module_init(init_ch_module);
1015 module_exit(exit_ch_module);
1016
1017 /*
1018  * Local variables:
1019  * c-basic-offset: 8
1020  * End:
1021  */