root/drivers/scsi/ch.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ch_find_errno
  2. ch_do_scsi
  3. ch_elem_to_typecode
  4. ch_read_element_status
  5. ch_init_elem
  6. ch_readconfig
  7. ch_position
  8. ch_move
  9. ch_exchange
  10. ch_check_voltag
  11. ch_set_voltag
  12. ch_gstatus
  13. ch_destroy
  14. ch_release
  15. ch_open
  16. ch_checkrange
  17. ch_ioctl
  18. ch_probe
  19. ch_remove
  20. init_ch_module
  21. exit_ch_module

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

/* [<][>][^][v][top][bottom][index][help] */