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. rw_intr
  3. sr_open
  4. do_sr_request
  5. 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 
  21 #include "scsi.h"
  22 #include "sr.h"
  23 
  24 #define MAJOR_NR 11
  25 
  26 #include "../blk.h"
  27 
  28 #define MAX_RETRIES 0
  29 #define SR_TIMEOUT 200
  30 
  31 int NR_SR=0;
  32 Scsi_CD scsi_CDs[MAX_SR];
  33 static int sr_sizes[MAX_SR << 4];
  34 static unsigned long int this_count;
  35 
  36 struct block_buffer
  37         {
  38         unsigned        block;
  39         unsigned        start;
  40         unsigned        use:1;
  41         unsigned char   buffer[2048];
  42         };
  43 
  44 static struct block_buffer bb[MAX_SR];
  45 
  46 static int sr_result;
  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 }
  56 
  57 static struct file_operations sr_fops = 
  58 {
  59         NULL,                   /* lseek - default */
  60         block_read,             /* read - general block-dev read */
  61         block_write,            /* write - general block-dev write */
  62         NULL,                   /* readdir - bad */
  63         NULL,                   /* select */
  64         sr_ioctl,               /* ioctl */
  65         sr_open,                /* no special open code */
  66         sr_release              /* release */
  67 };
  68 
  69 /*
  70  * The sense_buffer is where we put data for all mode sense commands performed.
  71  */
  72 
  73 static unsigned char sense_buffer[255];
  74 
  75 /*
  76  * rw_intr is the interrupt routine for the device driver.  It will be notified on the 
  77  * end of a SCSI read / write, and will take on of several actions based on success or failure.
  78  */
  79 
  80 static void rw_intr (int host, int result)
     /* [previous][next][first][last][top][bottom][index][help] */
  81 {
  82         if (SR_HOST != host)            
  83                 {
  84                 panic ("sr.o : rw_intr() recieving interrupt for different host.");
  85                 }
  86 
  87         if (!result)
  88                 { /* No error */
  89                 if (bb[DEVICE_NR(CURRENT->dev)].use)
  90                         {
  91                         memcpy((char *)CURRENT->buffer, 
  92                                bb[DEVICE_NR(CURRENT->dev)].buffer + 
  93                                (bb[DEVICE_NR(CURRENT->dev)].start << 9), 
  94                                this_count << 9);
  95                         }
  96 
  97                 CURRENT->nr_sectors -= this_count;
  98 
  99 #ifdef DEBUG
 100                 printk("(%x %x %x) ",CURRENT->bh, CURRENT->nr_sectors, 
 101                        this_count);
 102 #endif
 103                 if (CURRENT->nr_sectors)
 104                         {        
 105                         CURRENT->sector += this_count;
 106                         CURRENT->errors = 0;
 107                         if (!CURRENT->bh)
 108                           {
 109                             (char *) CURRENT->buffer += this_count << 9;
 110                           } else {
 111                             end_request(1);
 112                             do_sr_request();
 113                           }
 114                         }
 115                 else 
 116                         {
 117                         end_request(1);  /* All done */
 118                         do_sr_request();
 119                         } 
 120                 }
 121 
 122         /* We only come through here if we have an error of some kind */
 123 
 124         if (driver_byte(result) != 0) {
 125                 bb[DEVICE_NR(CURRENT->dev)].block = -1;
 126                 
 127                 if ((sense_buffer[0] & 0x7f) == 0x70) {
 128                         if ((sense_buffer[2] & 0xf) == UNIT_ATTENTION) {
 129                                 /* detected disc change.  set a bit and quietly refuse  */
 130                                 /* further access.                                      */
 131                     
 132                                 scsi_CDs[DEVICE_NR(CURRENT->dev)].changed = 1;
 133                                 end_request(0);
 134                                 return;
 135                         }
 136                 }
 137             
 138                 if (sense_buffer[2] == ILLEGAL_REQUEST) {
 139                         printk("CD-ROM error: Drive reports ILLEGAL REQUEST.\n");
 140                         if (scsi_CDs[DEVICE_NR(CURRENT->dev)].ten) {
 141                                 scsi_CDs[DEVICE_NR(CURRENT->dev)].ten = 0;
 142                                 do_sr_request();
 143                                 result = 0;
 144                                 return;
 145                         } else {
 146                                 end_request(0);
 147                                 do_sr_request(); /* Do next request */
 148                                 return;
 149                         }
 150 
 151                 }
 152 
 153                 if (sense_buffer[2] == NOT_READY) {
 154                         printk("CDROM not ready.  Make sure you have a disc in the drive.\n");
 155                         end_request(0);
 156                         do_sr_request(); /* Do next request */
 157                         return;
 158                 };
 159               }
 160         
 161         /* We only get this far if we have an error we have not recognized */
 162         if(result) {
 163           printk("SCSI CD error : host %d id %d lun %d return code = %03x\n", 
 164                  scsi_CDs[DEVICE_NR(CURRENT->dev)].device->host_no, 
 165                  scsi_CDs[DEVICE_NR(CURRENT->dev)].device->id,
 166                  scsi_CDs[DEVICE_NR(CURRENT->dev)].device->lun,
 167                  result);
 168             
 169         if (status_byte(result) == CHECK_CONDITION)
 170             printk("\tSense class %x, sense error %x, extended sense %x\n",
 171                  sense_class(sense_buffer[0]), 
 172                  sense_error(sense_buffer[0]),
 173                  sense_buffer[2] & 0xf);
 174         
 175         end_request(0);
 176         do_sr_request();
 177         }
 178 }
 179 
 180 static int sr_open(struct inode * inode, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 181 {
 182         if (filp->f_mode)
 183                 check_disk_change(inode->i_rdev);
 184         return 0;
 185 }
 186 
 187 /*
 188  * do_sr_request() is the request handler function for the sr driver.  Its function in life 
 189  * is to take block device requests, and translate them to SCSI commands.
 190  */
 191         
 192 void do_sr_request (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 193 {
 194         unsigned int dev, block, realcount;
 195         unsigned char cmd[10], *buffer, tries;
 196 
 197         tries = 2;
 198 
 199       repeat:
 200         INIT_REQUEST;
 201         dev =  MINOR(CURRENT->dev);
 202         block = CURRENT->sector;        
 203 
 204         bb[dev].start = block % 4;
 205         block = block / 4;
 206 
 207         if (dev >= NR_SR)
 208                 {
 209                 /* printk("CD-ROM request error: invalid device.\n");                   */
 210                 end_request(0);
 211                 tries = 2;
 212                 goto repeat;
 213                 }
 214 
 215         if (!scsi_CDs[dev].use)
 216                 {
 217                 /* printk("CD-ROM request error: device marked not in use.\n");         */
 218                 end_request(0);
 219                 tries = 2;
 220                 goto repeat;
 221                 }
 222 
 223         if (scsi_CDs[dev].changed)
 224                 {
 225 /* 
 226  * quietly refuse to do anything to a changed disc until the changed bit has been reset
 227  */
 228                 /* printk("CD-ROM has been changed.  Prohibiting further I/O.\n");      */
 229                 end_request(0);
 230                 tries = 2;
 231                 goto repeat;
 232                 }
 233         
 234         if (!CURRENT->bh)       
 235                 this_count = CURRENT->nr_sectors;
 236         else
 237                 this_count = (CURRENT->bh->b_size / 512);
 238 
 239         if (bb[dev].start)
 240                 {                                 
 241                 bb[dev].use = 1;
 242 
 243                 this_count = ((this_count > 4 - bb[dev].start) ? 
 244                               (4 - bb[dev].start) : (this_count));
 245 
 246                 if (bb[dev].block == block)
 247                         {
 248                           rw_intr(SR_HOST, 0);
 249                           return;
 250                         }
 251 
 252                 buffer = bb[dev].buffer;
 253                 bb[dev].block = block;
 254                 } 
 255         else if (this_count < 4)
 256                 {
 257                 bb[dev].use = 1;
 258 
 259                 if (bb[dev].block == block)
 260                         {
 261                           rw_intr(SR_HOST, 0);
 262                           return;
 263                         }
 264 
 265                 buffer = bb[dev].buffer;
 266                 bb[dev].block = block;
 267                 }
 268         else
 269                 {
 270                 this_count -= this_count % 4;
 271                 buffer = CURRENT->buffer;
 272                 bb[dev].use = 0;
 273                 }
 274 
 275         realcount = (this_count + 3) / 4;
 276 
 277         switch (CURRENT->cmd)
 278                 {
 279                 case WRITE:             
 280                         end_request(0);
 281                         goto repeat;
 282                         break;
 283                 case READ : 
 284                         cmd[0] = READ_6;
 285                         break;
 286                 default : 
 287                         printk ("Unknown sr command %d\r\n", CURRENT->cmd);
 288                         panic("");
 289                 }
 290         
 291         cmd[1] = (SR_LUN << 5) & 0xe0;
 292 
 293         if (((realcount > 0xff) || (block > 0x1fffff)) && scsi_CDs[dev].ten) 
 294                 {
 295                 if (realcount > 0xffff)
 296                         {
 297                         realcount = 0xffff;
 298                         this_count = realcount * 4;
 299                         }
 300 
 301                 cmd[0] += READ_10 - READ_6 ;
 302                 cmd[2] = (unsigned char) (block >> 24) & 0xff;
 303                 cmd[3] = (unsigned char) (block >> 16) & 0xff;
 304                 cmd[4] = (unsigned char) (block >> 8) & 0xff;
 305                 cmd[5] = (unsigned char) block & 0xff;
 306                 cmd[6] = cmd[9] = 0;
 307                 cmd[7] = (unsigned char) (realcount >> 8) & 0xff;
 308                 cmd[8] = (unsigned char) realcount & 0xff;
 309                 }
 310         else
 311                 {
 312                 if (realcount > 0xff)
 313                         {
 314                         realcount = 0xff;
 315                         this_count = realcount * 4;
 316                         }
 317         
 318                 cmd[1] |= (unsigned char) ((block >> 16) & 0x1f);
 319                 cmd[2] = (unsigned char) ((block >> 8) & 0xff);
 320                 cmd[3] = (unsigned char) block & 0xff;
 321                 cmd[4] = (unsigned char) realcount;
 322                 cmd[5] = 0;
 323                 }   
 324 
 325         scsi_do_cmd (SR_HOST, SR_ID, (void *) cmd, buffer, realcount << 11, 
 326                      rw_intr, SR_TIMEOUT, sense_buffer, MAX_RETRIES);
 327 }
 328 
 329 void sr_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 330 {
 331         int i;
 332 
 333         for (i = 0; i < NR_SR; ++i)
 334                 {
 335                 scsi_CDs[i].capacity = 0x1fffff;
 336                 scsi_CDs[i].sector_size = 2048;
 337                 scsi_CDs[i].use = 1;
 338                 scsi_CDs[i].ten = 1;
 339                 scsi_CDs[i].remap = 1;
 340                 scsi_CDs[i].changed = 0;
 341                 sr_sizes[i] = scsi_CDs[i].capacity;
 342 
 343                 bb[i].block = -1;
 344                 }
 345 
 346         blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
 347         blk_size[MAJOR_NR] = sr_sizes;  
 348         blkdev_fops[MAJOR_NR] = &sr_fops; 
 349 }       
 350 #endif
 351 
 352 
 353 
 354 
 355 

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