root/kernel/blk_drv/scsi/sr.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sr_release
  2. check_cdrom_media_change
  3. rw_intr
  4. sr_open
  5. do_sr_request
  6. sr_init

   1 /*
   2  *      sr.c by David Giller
   3  *
   4  *      adapted from:
   5  *      sd.c Copyright (C) 1992 Drew Eckhardt 
   6  *      Linux scsi disk driver by
   7  *              Drew Eckhardt 
   8  *
   9  *      <drew@colorado.edu>
  10  */
  11 
  12 #include <linux/config.h>
  13 
  14 #ifdef CONFIG_BLK_DEV_SR
  15 
  16 #include <linux/fs.h>
  17 #include <linux/kernel.h>
  18 #include <linux/sched.h>
  19 #include <linux/string.h>
  20 #include <linux/errno.h>
  21 
  22 #include "scsi.h"
  23 #include "sr.h"
  24 #include "scsi_ioctl.h"   /* For the door lock/unlock commands */
  25 
  26 #define MAJOR_NR 11
  27 
  28 #include "../blk.h"
  29 
  30 #define MAX_RETRIES 0
  31 #define SR_TIMEOUT 200
  32 
  33 int NR_SR=0;
  34 Scsi_CD scsi_CDs[MAX_SR];
  35 static int sr_sizes[MAX_SR << 4];
  36 static unsigned long int this_count;
  37 
  38 struct block_buffer
  39         {
  40         unsigned        block;
  41         unsigned        start;
  42         unsigned        use:1;
  43         unsigned char   buffer[2048];
  44         };
  45 
  46 static struct block_buffer * bb;
  47 
  48 static int sr_open(struct inode *, struct file *);
  49 
  50 extern int sr_ioctl(struct inode *, struct file *, unsigned int, unsigned int);
  51 
  52 static void sr_release(struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
  53 {
  54         sync_dev(inode->i_rdev);
  55         if(! --scsi_CDs[MINOR(inode->i_rdev)].device->access_count)
  56           sr_ioctl(inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0);
  57 }
  58 
  59 static struct file_operations sr_fops = 
  60 {
  61         NULL,                   /* lseek - default */
  62         block_read,             /* read - general block-dev read */
  63         block_write,            /* write - general block-dev write */
  64         NULL,                   /* readdir - bad */
  65         NULL,                   /* select */
  66         sr_ioctl,               /* ioctl */
  67         NULL,                   /* mmap */
  68         sr_open,                /* no special open code */
  69         sr_release              /* release */
  70 };
  71 
  72 /*
  73  * This function checks to see if the media has been changed in the
  74  * CDROM drive.  It is possible that we have already sensed a change,
  75  * or the drive may have sensed one and not yet reported it.  We must
  76  * be ready for either case. This function always reports the current
  77  * value of the changed bit.  If flag is 0, then the changed bit is reset.
  78  * This function could be done as an ioctl, but we would need to have
  79  * an inode for that to work, and we do not always have one.
  80  */
  81 
  82 int check_cdrom_media_change(int full_dev, int flag){
     /* [previous][next][first][last][top][bottom][index][help] */
  83         int retval, target;
  84         struct inode inode;
  85 
  86         target =  MINOR(full_dev);
  87 
  88         if (target >= NR_SR) {
  89                 printk("CD-ROM request error: invalid device.\n");
  90                 return 0;
  91         };
  92 
  93         inode.i_rdev = full_dev;  /* This is all we really need here */
  94         retval = sr_ioctl(&inode, NULL, SCSI_IOCTL_TEST_UNIT_READY, 0);
  95 
  96         if(retval){ /* Unable to test, unit probably not ready.  This usually
  97                      means there is no disc in the drive.  Mark as changed,
  98                      and we will figure it out later once the drive is
  99                      available again.  */
 100 
 101           scsi_CDs[target].device->changed = 1;
 102           return 1; /* This will force a flush, if called from
 103                        check_disk_change */
 104         };
 105 
 106         retval = scsi_CDs[target].device->changed;
 107         if(!flag) scsi_CDs[target].device->changed = 0;
 108         return retval;
 109 }
 110 
 111 /*
 112  * The sense_buffer is where we put data for all mode sense commands performed.
 113  */
 114 static unsigned char sense_buffer[255];
 115 
 116 /*
 117  * rw_intr is the interrupt routine for the device driver.  It will be notified on the 
 118  * end of a SCSI read / write, and will take on of several actions based on success or failure.
 119  */
 120 
 121 static void rw_intr (int host, int result)
     /* [previous][next][first][last][top][bottom][index][help] */
 122 {
 123         if (SR_HOST != host)            
 124                 {
 125                 panic ("sr.o : rw_intr() recieving interrupt for different host.");
 126                 }
 127 
 128         if (!result)
 129                 { /* No error */
 130                 if (bb[DEVICE_NR(CURRENT->dev)].use)
 131                         {
 132                         memcpy((char *)CURRENT->buffer, 
 133                                bb[DEVICE_NR(CURRENT->dev)].buffer + 
 134                                (bb[DEVICE_NR(CURRENT->dev)].start << 9), 
 135                                this_count << 9);
 136                         }
 137 
 138                 CURRENT->nr_sectors -= this_count;
 139 
 140 #ifdef DEBUG
 141                 printk("(%x %x %x) ",CURRENT->bh, CURRENT->nr_sectors, 
 142                        this_count);
 143 #endif
 144                 if (CURRENT->nr_sectors)
 145                         {        
 146                         CURRENT->sector += this_count;
 147                         CURRENT->errors = 0;
 148                         if (!CURRENT->bh)
 149                           {
 150                             (char *) CURRENT->buffer += this_count << 9;
 151                           } else {
 152                             end_request(1);
 153                             do_sr_request();
 154                           }
 155                         }
 156                 else 
 157                         {
 158                         end_request(1);  /* All done */
 159                         do_sr_request();
 160                         } 
 161                 }
 162 
 163         /* We only come through here if we have an error of some kind */
 164 
 165         if (driver_byte(result) != 0) {
 166                 bb[DEVICE_NR(CURRENT->dev)].block = -1;
 167                 
 168                 if ((sense_buffer[0] & 0x7f) == 0x70) {
 169                         if ((sense_buffer[2] & 0xf) == UNIT_ATTENTION) {
 170                                 /* detected disc change.  set a bit and quietly refuse  */
 171                                 /* further access.                                      */
 172                     
 173                                 scsi_CDs[DEVICE_NR(CURRENT->dev)].device->changed = 1;
 174                                 end_request(0);
 175                                 do_sr_request();
 176                                 return;
 177                         }
 178                 }
 179             
 180                 if (sense_buffer[2] == ILLEGAL_REQUEST) {
 181                         printk("CD-ROM error: Drive reports ILLEGAL REQUEST.\n");
 182                         if (scsi_CDs[DEVICE_NR(CURRENT->dev)].ten) {
 183                                 scsi_CDs[DEVICE_NR(CURRENT->dev)].ten = 0;
 184                                 do_sr_request();
 185                                 result = 0;
 186                                 return;
 187                         } else {
 188                         printk("CD-ROM error: Drive reports %d.\n", sense_buffer[2]);                           end_request(0);
 189                                 do_sr_request(); /* Do next request */
 190                                 return;
 191                         }
 192 
 193                 }
 194 
 195                 if (sense_buffer[2] == NOT_READY) {
 196                         printk("CDROM not ready.  Make sure you have a disc in the drive.\n");
 197                         end_request(0);
 198                         do_sr_request(); /* Do next request */
 199                         return;
 200                 };
 201               }
 202         
 203         /* We only get this far if we have an error we have not recognized */
 204         if(result) {
 205           printk("SCSI CD error : host %d id %d lun %d return code = %03x\n", 
 206                  scsi_CDs[DEVICE_NR(CURRENT->dev)].device->host_no, 
 207                  scsi_CDs[DEVICE_NR(CURRENT->dev)].device->id,
 208                  scsi_CDs[DEVICE_NR(CURRENT->dev)].device->lun,
 209                  result);
 210             
 211         if (status_byte(result) == CHECK_CONDITION)
 212             printk("\tSense class %x, sense error %x, extended sense %x\n",
 213                  sense_class(sense_buffer[0]), 
 214                  sense_error(sense_buffer[0]),
 215                  sense_buffer[2] & 0xf);
 216         
 217         end_request(0);
 218         do_sr_request();
 219         }
 220 }
 221 
 222 static int sr_open(struct inode * inode, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 223 {
 224         if(MINOR(inode->i_rdev) >= NR_SR ||
 225            !scsi_CDs[MINOR(inode->i_rdev)].device) return -EACCES;   /* No such device */
 226 
 227         check_disk_change(inode->i_rdev);
 228 
 229         if(!scsi_CDs[MINOR(inode->i_rdev)].device->access_count++)
 230           sr_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0);
 231         return 0;
 232 }
 233 
 234 /*
 235  * do_sr_request() is the request handler function for the sr driver.  Its function in life 
 236  * is to take block device requests, and translate them to SCSI commands.
 237  */
 238         
 239 void do_sr_request (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 240 {
 241         unsigned int dev, block, realcount;
 242         unsigned char cmd[10], *buffer, tries;
 243 
 244         tries = 2;
 245 
 246       repeat:
 247         INIT_REQUEST;
 248         dev =  MINOR(CURRENT->dev);
 249         block = CURRENT->sector;        
 250 
 251         bb[dev].start = block % 4;
 252         block = block / 4;
 253 
 254         if (dev >= NR_SR)
 255                 {
 256                 /* printk("CD-ROM request error: invalid device.\n");                   */
 257                 end_request(0);
 258                 tries = 2;
 259                 goto repeat;
 260                 }
 261 
 262         if (!scsi_CDs[dev].use)
 263                 {
 264                 /* printk("CD-ROM request error: device marked not in use.\n");         */
 265                 end_request(0);
 266                 tries = 2;
 267                 goto repeat;
 268                 }
 269 
 270         if (scsi_CDs[dev].device->changed)
 271                 {
 272 /* 
 273  * quietly refuse to do anything to a changed disc until the changed bit has been reset
 274  */
 275                 /* printk("CD-ROM has been changed.  Prohibiting further I/O.\n");      */
 276                 end_request(0);
 277                 tries = 2;
 278                 goto repeat;
 279                 }
 280         
 281         if (!CURRENT->bh)       
 282                 this_count = CURRENT->nr_sectors;
 283         else
 284                 this_count = (CURRENT->bh->b_size / 512);
 285 
 286         if (bb[dev].start)
 287                 {                                 
 288                 bb[dev].use = 1;
 289 
 290                 this_count = ((this_count > 4 - bb[dev].start) ? 
 291                               (4 - bb[dev].start) : (this_count));
 292 
 293                 if (bb[dev].block == block)
 294                         {
 295                           rw_intr(SR_HOST, 0);
 296                           return;
 297                         }
 298 
 299                 buffer = bb[dev].buffer;
 300                 bb[dev].block = block;
 301                 } 
 302         else if (this_count < 4)
 303                 {
 304                 bb[dev].use = 1;
 305 
 306                 if (bb[dev].block == block)
 307                         {
 308                           rw_intr(SR_HOST, 0);
 309                           return;
 310                         }
 311 
 312                 buffer = bb[dev].buffer;
 313                 bb[dev].block = block;
 314                 }
 315         else
 316                 {
 317                 this_count -= this_count % 4;
 318                 buffer = CURRENT->buffer;
 319                 bb[dev].use = 0;
 320                 }
 321 
 322         realcount = (this_count + 3) / 4;
 323 
 324         switch (CURRENT->cmd)
 325                 {
 326                 case WRITE:             
 327                         end_request(0);
 328                         goto repeat;
 329                         break;
 330                 case READ : 
 331                         cmd[0] = READ_6;
 332                         break;
 333                 default : 
 334                         printk ("Unknown sr command %d\r\n", CURRENT->cmd);
 335                         panic("");
 336                 }
 337         
 338         cmd[1] = (SR_LUN << 5) & 0xe0;
 339 
 340         if (((realcount > 0xff) || (block > 0x1fffff)) && scsi_CDs[dev].ten) 
 341                 {
 342                 if (realcount > 0xffff)
 343                         {
 344                         realcount = 0xffff;
 345                         this_count = realcount * 4;
 346                         }
 347 
 348                 cmd[0] += READ_10 - READ_6 ;
 349                 cmd[2] = (unsigned char) (block >> 24) & 0xff;
 350                 cmd[3] = (unsigned char) (block >> 16) & 0xff;
 351                 cmd[4] = (unsigned char) (block >> 8) & 0xff;
 352                 cmd[5] = (unsigned char) block & 0xff;
 353                 cmd[6] = cmd[9] = 0;
 354                 cmd[7] = (unsigned char) (realcount >> 8) & 0xff;
 355                 cmd[8] = (unsigned char) realcount & 0xff;
 356                 }
 357         else
 358                 {
 359                 if (realcount > 0xff)
 360                         {
 361                         realcount = 0xff;
 362                         this_count = realcount * 4;
 363                         }
 364         
 365                 cmd[1] |= (unsigned char) ((block >> 16) & 0x1f);
 366                 cmd[2] = (unsigned char) ((block >> 8) & 0xff);
 367                 cmd[3] = (unsigned char) block & 0xff;
 368                 cmd[4] = (unsigned char) realcount;
 369                 cmd[5] = 0;
 370                 }   
 371 
 372         scsi_do_cmd (SR_HOST, SR_ID, (void *) cmd, buffer, realcount << 11, 
 373                      rw_intr, SR_TIMEOUT, sense_buffer, MAX_RETRIES);
 374 }
 375 
 376 unsigned long sr_init(unsigned long memory_start, unsigned long memory_end)
     /* [previous][next][first][last][top][bottom][index][help] */
 377 {
 378         int i;
 379 
 380         bb = (struct block_buffer *) memory_start;
 381         memory_start += NR_SR * sizeof(struct block_buffer);
 382 
 383         for (i = 0; i < NR_SR; ++i)
 384                 {
 385                 scsi_CDs[i].capacity = 0x1fffff;
 386                 scsi_CDs[i].sector_size = 2048;
 387                 scsi_CDs[i].use = 1;
 388                 scsi_CDs[i].ten = 1;
 389                 scsi_CDs[i].remap = 1;
 390                 sr_sizes[i] = scsi_CDs[i].capacity;
 391 
 392                 bb[i].block = -1;
 393                 }
 394 
 395         blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
 396         blk_size[MAJOR_NR] = sr_sizes;  
 397         blkdev_fops[MAJOR_NR] = &sr_fops; 
 398         return memory_start;
 399 }       
 400 #endif
 401 
 402 
 403 
 404 
 405 

/* [previous][next][first][last][top][bottom][index][help] */