2  * SCSI Media Changer device driver for Linux 2.6
 
   4  *     (c) 1996-2003 Gerd Knorr <kraxel@bytesex.org>
 
  10 #include <linux/module.h>
 
  11 #include <linux/init.h>
 
  13 #include <linux/kernel.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>
 
  26 #include <scsi/scsi.h>
 
  27 #include <scsi/scsi_cmnd.h>
 
  28 #include <scsi/scsi_driver.h>
 
  29 #include <scsi/scsi_ioctl.h>
 
  30 #include <scsi/scsi_host.h>
 
  31 #include <scsi/scsi_device.h>
 
  32 #include <scsi/scsi_eh.h>
 
  33 #include <scsi/scsi_dbg.h>
 
  37 #define CH_MAX_DEVS     128
 
  39 MODULE_DESCRIPTION("device driver for scsi media changer devices");
 
  40 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org>");
 
  41 MODULE_LICENSE("GPL");
 
  42 MODULE_ALIAS_CHARDEV_MAJOR(SCSI_CHANGER_MAJOR);
 
  45 module_param(init, int, 0444);
 
  46 MODULE_PARM_DESC(init, \
 
  47     "initialize element status on driver load (default: on)");
 
  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)");
 
  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)");
 
  59 static int verbose = 1;
 
  60 module_param(verbose, int, 0644);
 
  61 MODULE_PARM_DESC(verbose,"be verbose (default: on)");
 
  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)");
 
  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);
 
  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);
 
  79 static const char * vendor_labels[CH_TYPES-4] = {
 
  80         "v0", "v1", "v2", "v3"
 
  82 // module_param_string_array(vendor_labels, NULL, 0444);
 
  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)
 
  89 /* ------------------------------------------------------------------- */
 
  93 static struct class * ch_sysfs_class;
 
  96         struct list_head    list;
 
  99         struct scsi_device  *device;
 
 100         struct scsi_device  **dt;        /* ptrs to data transfer elements */
 
 101         u_int               firsts[CH_TYPES];
 
 102         u_int               counts[CH_TYPES];
 
 103         u_int               unit_attention;
 
 108 static DEFINE_IDR(ch_index_idr);
 
 109 static DEFINE_SPINLOCK(ch_index_lock);
 
 111 static const struct {
 
 117 /* Just filled in what looks right. Hav'nt checked any standard paper for
 
 118    these errno assignments, so they may be wrong... */
 
 120                 .sense  = ILLEGAL_REQUEST,
 
 123                 .errno  = EBADSLT, /* Invalid element address */
 
 125                 .sense  = ILLEGAL_REQUEST,
 
 128                 .errno  = EBADE,   /* Import or export element accessed */
 
 130                 .sense  = ILLEGAL_REQUEST,
 
 133                 .errno  = EXFULL,  /* Medium destination element full */
 
 135                 .sense  = ILLEGAL_REQUEST,
 
 138                 .errno  = EBADE,   /* Medium source element empty */
 
 140                 .sense  = ILLEGAL_REQUEST,
 
 143                 .errno  = EBADRQC, /* Invalid command operation code */
 
 149 /* ------------------------------------------------------------------- */
 
 151 static int ch_find_errno(struct scsi_sense_hdr *sshdr)
 
 155         /* Check to see if additional sense information is available */
 
 156         if (scsi_sense_valid(sshdr) &&
 
 158                 for (i = 0; ch_err[i].errno != 0; i++) {
 
 159                         if (ch_err[i].sense == sshdr->sense_key &&
 
 160                             ch_err[i].asc   == sshdr->asc &&
 
 161                             ch_err[i].ascq  == sshdr->ascq) {
 
 162                                 errno = -ch_err[i].errno;
 
 173 ch_do_scsi(scsi_changer *ch, unsigned char *cmd,
 
 174            void *buffer, unsigned buflength,
 
 175            enum dma_data_direction direction)
 
 177         int errno, retries = 0, timeout, result;
 
 178         struct scsi_sense_hdr sshdr;
 
 180         timeout = (cmd[0] == INITIALIZE_ELEMENT_STATUS)
 
 181                 ? timeout_init : timeout_move;
 
 186                 dprintk("command: ");
 
 187                 __scsi_print_command(cmd);
 
 190         result = scsi_execute_req(ch->device, cmd, direction, buffer,
 
 191                                   buflength, &sshdr, timeout * HZ,
 
 194         dprintk("result: 0x%x\n",result);
 
 195         if (driver_byte(result) & DRIVER_SENSE) {
 
 197                         scsi_print_sense_hdr(ch->name, &sshdr);
 
 198                 errno = ch_find_errno(&sshdr);
 
 200                 switch(sshdr.sense_key) {
 
 202                         ch->unit_attention = 1;
 
 211 /* ------------------------------------------------------------------------ */
 
 214 ch_elem_to_typecode(scsi_changer *ch, u_int elem)
 
 218         for (i = 0; i < CH_TYPES; i++) {
 
 219                 if (elem >= ch->firsts[i]  &&
 
 220                     elem <  ch->firsts[i] +
 
 228 ch_read_element_status(scsi_changer *ch, u_int elem, char *data)
 
 234         buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
 
 239         memset(cmd,0,sizeof(cmd));
 
 240         cmd[0] = READ_ELEMENT_STATUS;
 
 241         cmd[1] = (ch->device->lun << 5) |
 
 242                 (ch->voltags ? 0x10 : 0) |
 
 243                 ch_elem_to_typecode(ch,elem);
 
 244         cmd[2] = (elem >> 8) & 0xff;
 
 245         cmd[3] = elem        & 0xff;
 
 248         if (0 == (result = ch_do_scsi(ch, cmd, buffer, 256, DMA_FROM_DEVICE))) {
 
 249                 if (((buffer[16] << 8) | buffer[17]) != elem) {
 
 250                         dprintk("asked for element 0x%02x, got 0x%02x\n",
 
 251                                 elem,(buffer[16] << 8) | buffer[17]);
 
 255                 memcpy(data,buffer+16,16);
 
 259                         vprintk("device has no volume tag support\n");
 
 262                 dprintk("READ ELEMENT STATUS for element 0x%x failed\n",elem);
 
 269 ch_init_elem(scsi_changer *ch)
 
 274         vprintk("INITIALIZE ELEMENT STATUS, may take some time ...\n");
 
 275         memset(cmd,0,sizeof(cmd));
 
 276         cmd[0] = INITIALIZE_ELEMENT_STATUS;
 
 277         cmd[1] = ch->device->lun << 5;
 
 278         err = ch_do_scsi(ch, cmd, NULL, 0, DMA_NONE);
 
 279         vprintk("... finished\n");
 
 284 ch_readconfig(scsi_changer *ch)
 
 286         u_char  cmd[10], data[16];
 
 291         buffer = kzalloc(512, GFP_KERNEL | GFP_DMA);
 
 295         memset(cmd,0,sizeof(cmd));
 
 297         cmd[1] = ch->device->lun << 5;
 
 300         result = ch_do_scsi(ch, cmd, buffer, 255, DMA_FROM_DEVICE);
 
 303                 result  = ch_do_scsi(ch, cmd, buffer, 255, DMA_FROM_DEVICE);
 
 306                 ch->firsts[CHET_MT] =
 
 307                         (buffer[buffer[3]+ 6] << 8) | buffer[buffer[3]+ 7];
 
 308                 ch->counts[CHET_MT] =
 
 309                         (buffer[buffer[3]+ 8] << 8) | buffer[buffer[3]+ 9];
 
 310                 ch->firsts[CHET_ST] =
 
 311                         (buffer[buffer[3]+10] << 8) | buffer[buffer[3]+11];
 
 312                 ch->counts[CHET_ST] =
 
 313                         (buffer[buffer[3]+12] << 8) | buffer[buffer[3]+13];
 
 314                 ch->firsts[CHET_IE] =
 
 315                         (buffer[buffer[3]+14] << 8) | buffer[buffer[3]+15];
 
 316                 ch->counts[CHET_IE] =
 
 317                         (buffer[buffer[3]+16] << 8) | buffer[buffer[3]+17];
 
 318                 ch->firsts[CHET_DT] =
 
 319                         (buffer[buffer[3]+18] << 8) | buffer[buffer[3]+19];
 
 320                 ch->counts[CHET_DT] =
 
 321                         (buffer[buffer[3]+20] << 8) | buffer[buffer[3]+21];
 
 322                 vprintk("type #1 (mt): 0x%x+%d [medium transport]\n",
 
 324                         ch->counts[CHET_MT]);
 
 325                 vprintk("type #2 (st): 0x%x+%d [storage]\n",
 
 327                         ch->counts[CHET_ST]);
 
 328                 vprintk("type #3 (ie): 0x%x+%d [import/export]\n",
 
 330                         ch->counts[CHET_IE]);
 
 331                 vprintk("type #4 (dt): 0x%x+%d [data transfer]\n",
 
 333                         ch->counts[CHET_DT]);
 
 335                 vprintk("reading element address assigment page failed!\n");
 
 338         /* vendor specific element types */
 
 339         for (i = 0; i < 4; i++) {
 
 340                 if (0 == vendor_counts[i])
 
 342                 if (NULL == vendor_labels[i])
 
 344                 ch->firsts[CHET_V1+i] = vendor_firsts[i];
 
 345                 ch->counts[CHET_V1+i] = vendor_counts[i];
 
 346                 vprintk("type #%d (v%d): 0x%x+%d [%s, vendor specific]\n",
 
 347                         i+5,i+1,vendor_firsts[i],vendor_counts[i],
 
 351         /* look up the devices of the data transfer elements */
 
 352         ch->dt = kmalloc(ch->counts[CHET_DT]*sizeof(struct scsi_device),
 
 354         for (elem = 0; elem < ch->counts[CHET_DT]; elem++) {
 
 357                 if (elem < CH_DT_MAX  &&  -1 != dt_id[elem]) {
 
 360                         vprintk("dt 0x%x: [insmod option] ",
 
 361                                 elem+ch->firsts[CHET_DT]);
 
 362                 } else if (0 != ch_read_element_status
 
 363                            (ch,elem+ch->firsts[CHET_DT],data)) {
 
 364                         vprintk("dt 0x%x: READ ELEMENT STATUS failed\n",
 
 365                                 elem+ch->firsts[CHET_DT]);
 
 367                         vprintk("dt 0x%x: ",elem+ch->firsts[CHET_DT]);
 
 368                         if (data[6] & 0x80) {
 
 370                                         printk("not this SCSI bus\n");
 
 372                         } else if (0 == (data[6] & 0x30)) {
 
 374                                         printk("ID/LUN unknown\n");
 
 379                                 if (data[6] & 0x20) id  = data[7];
 
 380                                 if (data[6] & 0x10) lun = data[6] & 7;
 
 385                                 printk("ID %i, LUN %i, ",id,lun);
 
 387                                 scsi_device_lookup(ch->device->host,
 
 391                                 /* should not happen */
 
 393                                         printk("Huh? device not found!\n");
 
 396                                         printk("name: %8.8s %16.16s %4.4s\n",
 
 397                                                ch->dt[elem]->vendor,
 
 409 /* ------------------------------------------------------------------------ */
 
 412 ch_position(scsi_changer *ch, u_int trans, u_int elem, int rotate)
 
 416         dprintk("position: 0x%x\n",elem);
 
 418                 trans = ch->firsts[CHET_MT];
 
 419         memset(cmd,0,sizeof(cmd));
 
 420         cmd[0]  = POSITION_TO_ELEMENT;
 
 421         cmd[1]  = ch->device->lun << 5;
 
 422         cmd[2]  = (trans >> 8) & 0xff;
 
 423         cmd[3]  =  trans       & 0xff;
 
 424         cmd[4]  = (elem  >> 8) & 0xff;
 
 425         cmd[5]  =  elem        & 0xff;
 
 426         cmd[8]  = rotate ? 1 : 0;
 
 427         return ch_do_scsi(ch, cmd, NULL, 0, DMA_NONE);
 
 431 ch_move(scsi_changer *ch, u_int trans, u_int src, u_int dest, int rotate)
 
 435         dprintk("move: 0x%x => 0x%x\n",src,dest);
 
 437                 trans = ch->firsts[CHET_MT];
 
 438         memset(cmd,0,sizeof(cmd));
 
 439         cmd[0]  = MOVE_MEDIUM;
 
 440         cmd[1]  = ch->device->lun << 5;
 
 441         cmd[2]  = (trans >> 8) & 0xff;
 
 442         cmd[3]  =  trans       & 0xff;
 
 443         cmd[4]  = (src   >> 8) & 0xff;
 
 445         cmd[6]  = (dest  >> 8) & 0xff;
 
 446         cmd[7]  =  dest        & 0xff;
 
 447         cmd[10] = rotate ? 1 : 0;
 
 448         return ch_do_scsi(ch, cmd, NULL,0, DMA_NONE);
 
 452 ch_exchange(scsi_changer *ch, u_int trans, u_int src,
 
 453             u_int dest1, u_int dest2, int rotate1, int rotate2)
 
 457         dprintk("exchange: 0x%x => 0x%x => 0x%x\n",
 
 460                 trans = ch->firsts[CHET_MT];
 
 461         memset(cmd,0,sizeof(cmd));
 
 462         cmd[0]  = EXCHANGE_MEDIUM;
 
 463         cmd[1]  = ch->device->lun << 5;
 
 464         cmd[2]  = (trans >> 8) & 0xff;
 
 465         cmd[3]  =  trans       & 0xff;
 
 466         cmd[4]  = (src   >> 8) & 0xff;
 
 468         cmd[6]  = (dest1 >> 8) & 0xff;
 
 469         cmd[7]  =  dest1       & 0xff;
 
 470         cmd[8]  = (dest2 >> 8) & 0xff;
 
 471         cmd[9]  =  dest2       & 0xff;
 
 472         cmd[10] = (rotate1 ? 1 : 0) | (rotate2 ? 2 : 0);
 
 474         return ch_do_scsi(ch, cmd, NULL,0, DMA_NONE);
 
 478 ch_check_voltag(char *tag)
 
 482         for (i = 0; i < 32; i++) {
 
 483                 /* restrict to ascii */
 
 484                 if (tag[i] >= 0x7f || tag[i] < 0x20)
 
 486                 /* don't allow search wildcards */
 
 494 ch_set_voltag(scsi_changer *ch, u_int elem,
 
 495               int alternate, int clear, u_char *tag)
 
 501         buffer = kzalloc(512, GFP_KERNEL);
 
 505         dprintk("%s %s voltag: 0x%x => \"%s\"\n",
 
 506                 clear     ? "clear"     : "set",
 
 507                 alternate ? "alternate" : "primary",
 
 509         memset(cmd,0,sizeof(cmd));
 
 510         cmd[0]  = SEND_VOLUME_TAG;
 
 511         cmd[1] = (ch->device->lun << 5) |
 
 512                 ch_elem_to_typecode(ch,elem);
 
 513         cmd[2] = (elem >> 8) & 0xff;
 
 514         cmd[3] = elem        & 0xff;
 
 516                 ? (alternate ? 0x0d : 0x0c)
 
 517                 : (alternate ? 0x0b : 0x0a);
 
 521         memcpy(buffer,tag,32);
 
 522         ch_check_voltag(buffer);
 
 524         result = ch_do_scsi(ch, cmd, buffer, 256, DMA_TO_DEVICE);
 
 529 static int ch_gstatus(scsi_changer *ch, int type, unsigned char __user *dest)
 
 535         mutex_lock(&ch->lock);
 
 536         for (i = 0; i < ch->counts[type]; i++) {
 
 537                 if (0 != ch_read_element_status
 
 538                     (ch, ch->firsts[type]+i,data)) {
 
 542                 put_user(data[2], dest+i);
 
 543                 if (data[2] & CESTATUS_EXCEPT)
 
 544                         vprintk("element 0x%x: asc=0x%x, ascq=0x%x\n",
 
 546                                 (int)data[4],(int)data[5]);
 
 547                 retval = ch_read_element_status
 
 548                         (ch, ch->firsts[type]+i,data);
 
 552         mutex_unlock(&ch->lock);
 
 556 /* ------------------------------------------------------------------------ */
 
 559 ch_release(struct inode *inode, struct file *file)
 
 561         scsi_changer *ch = file->private_data;
 
 563         scsi_device_put(ch->device);
 
 564         file->private_data = NULL;
 
 569 ch_open(struct inode *inode, struct file *file)
 
 572         int minor = iminor(inode);
 
 574         spin_lock(&ch_index_lock);
 
 575         ch = idr_find(&ch_index_idr, minor);
 
 577         if (NULL == ch || scsi_device_get(ch->device)) {
 
 578                 spin_unlock(&ch_index_lock);
 
 581         spin_unlock(&ch_index_lock);
 
 583         file->private_data = ch;
 
 588 ch_checkrange(scsi_changer *ch, unsigned int type, unsigned int unit)
 
 590         if (type >= CH_TYPES  ||  unit >= ch->counts[type])
 
 595 static long ch_ioctl(struct file *file,
 
 596                     unsigned int cmd, unsigned long arg)
 
 598         scsi_changer *ch = file->private_data;
 
 600         void __user *argp = (void __user *)arg;
 
 605                 struct changer_params params;
 
 607                 params.cp_curpicker = 0;
 
 608                 params.cp_npickers  = ch->counts[CHET_MT];
 
 609                 params.cp_nslots    = ch->counts[CHET_ST];
 
 610                 params.cp_nportals  = ch->counts[CHET_IE];
 
 611                 params.cp_ndrives   = ch->counts[CHET_DT];
 
 613                 if (copy_to_user(argp, ¶ms, sizeof(params)))
 
 619                 struct changer_vendor_params vparams;
 
 621                 memset(&vparams,0,sizeof(vparams));
 
 622                 if (ch->counts[CHET_V1]) {
 
 623                         vparams.cvp_n1  = ch->counts[CHET_V1];
 
 624                         strncpy(vparams.cvp_label1,vendor_labels[0],16);
 
 626                 if (ch->counts[CHET_V2]) {
 
 627                         vparams.cvp_n2  = ch->counts[CHET_V2];
 
 628                         strncpy(vparams.cvp_label2,vendor_labels[1],16);
 
 630                 if (ch->counts[CHET_V3]) {
 
 631                         vparams.cvp_n3  = ch->counts[CHET_V3];
 
 632                         strncpy(vparams.cvp_label3,vendor_labels[2],16);
 
 634                 if (ch->counts[CHET_V4]) {
 
 635                         vparams.cvp_n4  = ch->counts[CHET_V4];
 
 636                         strncpy(vparams.cvp_label4,vendor_labels[3],16);
 
 638                 if (copy_to_user(argp, &vparams, sizeof(vparams)))
 
 645                 struct changer_position pos;
 
 647                 if (copy_from_user(&pos, argp, sizeof (pos)))
 
 650                 if (0 != ch_checkrange(ch, pos.cp_type, pos.cp_unit)) {
 
 651                         dprintk("CHIOPOSITION: invalid parameter\n");
 
 654                 mutex_lock(&ch->lock);
 
 655                 retval = ch_position(ch,0,
 
 656                                      ch->firsts[pos.cp_type] + pos.cp_unit,
 
 657                                      pos.cp_flags & CP_INVERT);
 
 658                 mutex_unlock(&ch->lock);
 
 664                 struct changer_move mv;
 
 666                 if (copy_from_user(&mv, argp, sizeof (mv)))
 
 669                 if (0 != ch_checkrange(ch, mv.cm_fromtype, mv.cm_fromunit) ||
 
 670                     0 != ch_checkrange(ch, mv.cm_totype,   mv.cm_tounit  )) {
 
 671                         dprintk("CHIOMOVE: invalid parameter\n");
 
 675                 mutex_lock(&ch->lock);
 
 676                 retval = ch_move(ch,0,
 
 677                                  ch->firsts[mv.cm_fromtype] + mv.cm_fromunit,
 
 678                                  ch->firsts[mv.cm_totype]   + mv.cm_tounit,
 
 679                                  mv.cm_flags & CM_INVERT);
 
 680                 mutex_unlock(&ch->lock);
 
 686                 struct changer_exchange mv;
 
 688                 if (copy_from_user(&mv, argp, sizeof (mv)))
 
 691                 if (0 != ch_checkrange(ch, mv.ce_srctype,  mv.ce_srcunit ) ||
 
 692                     0 != ch_checkrange(ch, mv.ce_fdsttype, mv.ce_fdstunit) ||
 
 693                     0 != ch_checkrange(ch, mv.ce_sdsttype, mv.ce_sdstunit)) {
 
 694                         dprintk("CHIOEXCHANGE: invalid parameter\n");
 
 698                 mutex_lock(&ch->lock);
 
 701                          ch->firsts[mv.ce_srctype]  + mv.ce_srcunit,
 
 702                          ch->firsts[mv.ce_fdsttype] + mv.ce_fdstunit,
 
 703                          ch->firsts[mv.ce_sdsttype] + mv.ce_sdstunit,
 
 704                          mv.ce_flags & CE_INVERT1, mv.ce_flags & CE_INVERT2);
 
 705                 mutex_unlock(&ch->lock);
 
 711                 struct changer_element_status ces;
 
 713                 if (copy_from_user(&ces, argp, sizeof (ces)))
 
 715                 if (ces.ces_type < 0 || ces.ces_type >= CH_TYPES)
 
 718                 return ch_gstatus(ch, ces.ces_type, ces.ces_data);
 
 723                 struct changer_get_element cge;
 
 729                 if (copy_from_user(&cge, argp, sizeof (cge)))
 
 732                 if (0 != ch_checkrange(ch, cge.cge_type, cge.cge_unit))
 
 734                 elem = ch->firsts[cge.cge_type] + cge.cge_unit;
 
 736                 buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
 
 739                 mutex_lock(&ch->lock);
 
 742                 memset(ch_cmd, 0, sizeof(ch_cmd));
 
 743                 ch_cmd[0] = READ_ELEMENT_STATUS;
 
 744                 ch_cmd[1] = (ch->device->lun << 5) |
 
 745                         (ch->voltags ? 0x10 : 0) |
 
 746                         ch_elem_to_typecode(ch,elem);
 
 747                 ch_cmd[2] = (elem >> 8) & 0xff;
 
 748                 ch_cmd[3] = elem        & 0xff;
 
 752                 result = ch_do_scsi(ch, ch_cmd, buffer, 256, DMA_FROM_DEVICE);
 
 754                         cge.cge_status = buffer[18];
 
 756                         if (buffer[18] & CESTATUS_EXCEPT) {
 
 759                         if (buffer[25] & 0x80) {
 
 760                                 cge.cge_flags |= CGE_SRC;
 
 761                                 if (buffer[25] & 0x40)
 
 762                                         cge.cge_flags |= CGE_INVERT;
 
 763                                 elem = (buffer[26]<<8) | buffer[27];
 
 764                                 for (i = 0; i < 4; i++) {
 
 765                                         if (elem >= ch->firsts[i] &&
 
 766                                             elem <  ch->firsts[i] + ch->counts[i]) {
 
 768                                                 cge.cge_srcunit = elem-ch->firsts[i];
 
 772                         if ((buffer[22] & 0x30) == 0x30) {
 
 773                                 cge.cge_flags |= CGE_IDLUN;
 
 774                                 cge.cge_id  = buffer[23];
 
 775                                 cge.cge_lun = buffer[22] & 7;
 
 777                         if (buffer[9] & 0x80) {
 
 778                                 cge.cge_flags |= CGE_PVOLTAG;
 
 779                                 memcpy(cge.cge_pvoltag,buffer+28,36);
 
 781                         if (buffer[9] & 0x40) {
 
 782                                 cge.cge_flags |= CGE_AVOLTAG;
 
 783                                 memcpy(cge.cge_avoltag,buffer+64,36);
 
 785                 } else if (ch->voltags) {
 
 787                         vprintk("device has no volume tag support\n");
 
 791                 mutex_unlock(&ch->lock);
 
 793                 if (copy_to_user(argp, &cge, sizeof (cge)))
 
 800                 mutex_lock(&ch->lock);
 
 801                 retval = ch_init_elem(ch);
 
 802                 mutex_unlock(&ch->lock);
 
 808                 struct changer_set_voltag csv;
 
 811                 if (copy_from_user(&csv, argp, sizeof(csv)))
 
 814                 if (0 != ch_checkrange(ch, csv.csv_type, csv.csv_unit)) {
 
 815                         dprintk("CHIOSVOLTAG: invalid parameter\n");
 
 818                 elem = ch->firsts[csv.csv_type] + csv.csv_unit;
 
 819                 mutex_lock(&ch->lock);
 
 820                 retval = ch_set_voltag(ch, elem,
 
 821                                        csv.csv_flags & CSV_AVOLTAG,
 
 822                                        csv.csv_flags & CSV_CLEARTAG,
 
 824                 mutex_unlock(&ch->lock);
 
 829                 return scsi_ioctl(ch->device, cmd, argp);
 
 836 struct changer_element_status32 {
 
 838         compat_uptr_t   ces_data;
 
 840 #define CHIOGSTATUS32  _IOW('c', 8,struct changer_element_status32)
 
 842 static long ch_ioctl_compat(struct file * file,
 
 843                             unsigned int cmd, unsigned long arg)
 
 845         scsi_changer *ch = file->private_data;
 
 857                 return ch_ioctl(file, cmd, arg);
 
 860                 struct changer_element_status32 ces32;
 
 861                 unsigned char __user *data;
 
 863                 if (copy_from_user(&ces32, (void __user *)arg, sizeof (ces32)))
 
 865                 if (ces32.ces_type < 0 || ces32.ces_type >= CH_TYPES)
 
 868                 data = compat_ptr(ces32.ces_data);
 
 869                 return ch_gstatus(ch, ces32.ces_type, data);
 
 872                 // return scsi_ioctl_compat(ch->device, cmd, (void*)arg);
 
 879 /* ------------------------------------------------------------------------ */
 
 881 static int ch_probe(struct device *dev)
 
 883         struct scsi_device *sd = to_scsi_device(dev);
 
 884         struct device *class_dev;
 
 885         int minor, ret = -ENOMEM;
 
 888         if (sd->type != TYPE_MEDIUM_CHANGER)
 
 891         ch = kzalloc(sizeof(*ch), GFP_KERNEL);
 
 895         if (!idr_pre_get(&ch_index_idr, GFP_KERNEL))
 
 898         spin_lock(&ch_index_lock);
 
 899         ret = idr_get_new(&ch_index_idr, ch, &minor);
 
 900         spin_unlock(&ch_index_lock);
 
 905         if (minor > CH_MAX_DEVS) {
 
 911         sprintf(ch->name,"ch%d",ch->minor);
 
 913         class_dev = device_create(ch_sysfs_class, dev,
 
 914                                   MKDEV(SCSI_CHANGER_MAJOR,ch->minor),
 
 916         if (IS_ERR(class_dev)) {
 
 917                 printk(KERN_WARNING "ch%d: device_create failed\n",
 
 919                 ret = PTR_ERR(class_dev);
 
 923         mutex_init(&ch->lock);
 
 929         dev_set_drvdata(dev, ch);
 
 930         sdev_printk(KERN_INFO, sd, "Attached scsi changer %s\n", ch->name);
 
 934         idr_remove(&ch_index_idr, minor);
 
 940 static int ch_remove(struct device *dev)
 
 942         scsi_changer *ch = dev_get_drvdata(dev);
 
 944         spin_lock(&ch_index_lock);
 
 945         idr_remove(&ch_index_idr, ch->minor);
 
 946         spin_unlock(&ch_index_lock);
 
 948         device_destroy(ch_sysfs_class, MKDEV(SCSI_CHANGER_MAJOR,ch->minor));
 
 954 static struct scsi_driver ch_template = {
 
 955         .owner          = THIS_MODULE,
 
 963 static const struct file_operations changer_fops = {
 
 964         .owner          = THIS_MODULE,
 
 966         .release        = ch_release,
 
 967         .unlocked_ioctl = ch_ioctl,
 
 969         .compat_ioctl   = ch_ioctl_compat,
 
 973 static int __init init_ch_module(void)
 
 977         printk(KERN_INFO "SCSI Media Changer driver v" VERSION " \n");
 
 978         ch_sysfs_class = class_create(THIS_MODULE, "scsi_changer");
 
 979         if (IS_ERR(ch_sysfs_class)) {
 
 980                 rc = PTR_ERR(ch_sysfs_class);
 
 983         rc = register_chrdev(SCSI_CHANGER_MAJOR,"ch",&changer_fops);
 
 985                 printk("Unable to get major %d for SCSI-Changer\n",
 
 989         rc = scsi_register_driver(&ch_template.gendrv);
 
 995         unregister_chrdev(SCSI_CHANGER_MAJOR, "ch");
 
 997         class_destroy(ch_sysfs_class);
 
1001 static void __exit exit_ch_module(void)
 
1003         scsi_unregister_driver(&ch_template.gendrv);
 
1004         unregister_chrdev(SCSI_CHANGER_MAJOR, "ch");
 
1005         class_destroy(ch_sysfs_class);
 
1006         idr_destroy(&ch_index_idr);
 
1009 module_init(init_ch_module);
 
1010 module_exit(exit_ch_module);