|
|
1.1 ! root 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: * <[email protected]> ! 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) ! 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) ! 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) ! 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) ! 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) ! 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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.