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