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