Showing error 1648

User: Jiri Slaby
Error type: Invalid Pointer Dereference
Error type description: A pointer which is invalid is being dereferenced
File location: drivers/scsi/ch.c
Line in file: 372
Project: Linux Kernel
Project version: 2.6.28
Tools: Smatch (1.59)
Entered: 2013-09-10 07:54:05 UTC


Source:

   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
  40MODULE_DESCRIPTION("device driver for scsi media changer devices");
  41MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org>");
  42MODULE_LICENSE("GPL");
  43MODULE_ALIAS_CHARDEV_MAJOR(SCSI_CHANGER_MAJOR);
  44
  45static int init = 1;
  46module_param(init, int, 0444);
  47MODULE_PARM_DESC(init, \
  48    "initialize element status on driver load (default: on)");
  49
  50static int timeout_move = 300;
  51module_param(timeout_move, int, 0644);
  52MODULE_PARM_DESC(timeout_move,"timeout for move commands "
  53                 "(default: 300 seconds)");
  54
  55static int timeout_init = 3600;
  56module_param(timeout_init, int, 0644);
  57MODULE_PARM_DESC(timeout_init,"timeout for INITIALIZE ELEMENT STATUS "
  58                 "(default: 3600 seconds)");
  59
  60static int verbose = 1;
  61module_param(verbose, int, 0644);
  62MODULE_PARM_DESC(verbose,"be verbose (default: on)");
  63
  64static int debug = 0;
  65module_param(debug, int, 0644);
  66MODULE_PARM_DESC(debug,"enable/disable debug messages, also prints more "
  67                 "detailed sense codes on scsi errors (default: off)");
  68
  69static int dt_id[CH_DT_MAX] = { [ 0 ... (CH_DT_MAX-1) ] = -1 };
  70static int dt_lun[CH_DT_MAX];
  71module_param_array(dt_id,  int, NULL, 0444);
  72module_param_array(dt_lun, int, NULL, 0444);
  73
  74/* tell the driver about vendor-specific slots */
  75static int vendor_firsts[CH_TYPES-4];
  76static int vendor_counts[CH_TYPES-4];
  77module_param_array(vendor_firsts, int, NULL, 0444);
  78module_param_array(vendor_counts, int, NULL, 0444);
  79
  80static 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
  94static struct class * ch_sysfs_class;
  95
  96typedef 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
 109static DEFINE_IDR(ch_index_idr);
 110static DEFINE_SPINLOCK(ch_index_lock);
 111
 112static 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
 152static 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
 173static int
 174ch_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
 214static int
 215ch_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
 228static int
 229ch_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
 269static int
 270ch_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
 284static int
 285ch_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
 412static int
 413ch_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
 431static int
 432ch_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
 452static int
 453ch_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
 478static void
 479ch_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
 494static int
 495ch_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
 530static 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
 559static int
 560ch_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
 569static int
 570ch_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
 591static int
 592ch_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
 599static 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
 840struct 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
 846static 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
 885static 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;
 937remove_idr:
 938        idr_remove(&ch_index_idr, minor);
 939free_ch:
 940        kfree(ch);
 941        return ret;
 942}
 943
 944static 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
 958static 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
 967static 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
 977static 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
1005static 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
1013module_init(init_ch_module);
1014module_exit(exit_ch_module);
1015
1016/*
1017 * Local variables:
1018 * c-basic-offset: 8
1019 * End:
1020 */