📄 sd.c
字号:
(unsigned long __user *)&loc->start)) return -EFAULT; return 0;}/** * sd_ioctl - process an ioctl * @inode: only i_rdev/i_bdev members may be used * @filp: only f_mode and f_flags may be used * @cmd: ioctl command number * @arg: this is third argument given to ioctl(2) system call. * Often contains a pointer. * * Returns 0 if successful (some ioctls return postive numbers on * success as well). Returns a negated errno value in case of error. * * Note: most ioctls are forward onto the block subsystem or further * down in the scsi subsytem. **/static int sd_ioctl(struct inode * inode, struct file * filp, unsigned int cmd, unsigned long arg){ struct block_device *bdev = inode->i_bdev; struct gendisk *disk = bdev->bd_disk; struct scsi_device *sdp = scsi_disk(disk)->device; void __user *p = (void __user *)arg; int error; SCSI_LOG_IOCTL(1, printk("sd_ioctl: disk=%s, cmd=0x%x\n", disk->disk_name, cmd)); /* * If we are in the middle of error recovery, don't let anyone * else try and use this device. Also, if error recovery fails, it * may try and take the device offline, in which case all further * access to the device is prohibited. */ if (!scsi_block_when_processing_errors(sdp)) return -ENODEV; if (cmd == HDIO_GETGEO) { if (!arg) return -EINVAL; return sd_hdio_getgeo(bdev, p); } /* * Send SCSI addressing ioctls directly to mid level, send other * ioctls to block level and then onto mid level if they can't be * resolved. */ switch (cmd) { case SCSI_IOCTL_GET_IDLUN: case SCSI_IOCTL_GET_BUS_NUMBER: return scsi_ioctl(sdp, cmd, p); default: error = scsi_cmd_ioctl(filp, disk, cmd, p); if (error != -ENOTTY) return error; } return scsi_ioctl(sdp, cmd, p);}static void set_media_not_present(struct scsi_disk *sdkp){ sdkp->media_present = 0; sdkp->capacity = 0; sdkp->device->changed = 1;}/** * sd_media_changed - check if our medium changed * @disk: kernel device descriptor * * Returns 0 if not applicable or no change; 1 if change * * Note: this function is invoked from the block subsystem. **/static int sd_media_changed(struct gendisk *disk){ struct scsi_disk *sdkp = scsi_disk(disk); struct scsi_device *sdp = sdkp->device; int retval; SCSI_LOG_HLQUEUE(3, printk("sd_media_changed: disk=%s\n", disk->disk_name)); if (!sdp->removable) return 0; /* * If the device is offline, don't send any commands - just pretend as * if the command failed. If the device ever comes back online, we * can deal with it then. It is only because of unrecoverable errors * that we would ever take a device offline in the first place. */ if (!scsi_device_online(sdp)) goto not_present; /* * Using TEST_UNIT_READY enables differentiation between drive with * no cartridge loaded - NOT READY, drive with changed cartridge - * UNIT ATTENTION, or with same cartridge - GOOD STATUS. * * Drives that auto spin down. eg iomega jaz 1G, will be started * by sd_spinup_disk() from sd_revalidate_disk(), which happens whenever * sd_revalidate() is called. */ retval = -ENODEV; if (scsi_block_when_processing_errors(sdp)) retval = scsi_test_unit_ready(sdp, SD_TIMEOUT, SD_MAX_RETRIES); /* * Unable to test, unit probably not ready. This usually * means there is no disc in the drive. Mark as changed, * and we will figure it out later once the drive is * available again. */ if (retval) goto not_present; /* * For removable scsi disk we have to recognise the presence * of a disk in the drive. This is kept in the struct scsi_disk * struct and tested at open ! Daniel Roche (dan@lectra.fr) */ sdkp->media_present = 1; retval = sdp->changed; sdp->changed = 0; return retval;not_present: set_media_not_present(sdkp); return 1;}static int sd_sync_cache(struct scsi_device *sdp){ struct scsi_request *sreq; int retries, res; if (!scsi_device_online(sdp)) return -ENODEV; sreq = scsi_allocate_request(sdp, GFP_KERNEL); if (!sreq) { printk("FAILED\n No memory for request\n"); return -ENOMEM; } sreq->sr_data_direction = DMA_NONE; for (retries = 3; retries > 0; --retries) { unsigned char cmd[10] = { 0 }; cmd[0] = SYNCHRONIZE_CACHE; /* * Leave the rest of the command zero to indicate * flush everything. */ scsi_wait_req(sreq, cmd, NULL, 0, SD_TIMEOUT, SD_MAX_RETRIES); if (sreq->sr_result == 0) break; } res = sreq->sr_result; if (res) { printk(KERN_WARNING "FAILED\n status = %x, message = %02x, " "host = %d, driver = %02x\n ", status_byte(res), msg_byte(res), host_byte(res), driver_byte(res)); if (driver_byte(res) & DRIVER_SENSE) scsi_print_req_sense("sd", sreq); } scsi_release_request(sreq); return res;}static int sd_issue_flush(struct device *dev, sector_t *error_sector){ struct scsi_device *sdp = to_scsi_device(dev); struct scsi_disk *sdkp = dev_get_drvdata(dev); if (!sdkp) return -ENODEV; if (!sdkp->WCE) return 0; return sd_sync_cache(sdp);}static void sd_rescan(struct device *dev){ struct scsi_disk *sdkp = dev_get_drvdata(dev); sd_revalidate_disk(sdkp->disk);}static struct block_device_operations sd_fops = { .owner = THIS_MODULE, .open = sd_open, .release = sd_release, .ioctl = sd_ioctl, .media_changed = sd_media_changed, .revalidate_disk = sd_revalidate_disk,};/** * sd_rw_intr - bottom half handler: called when the lower level * driver has completed (successfully or otherwise) a scsi command. * @SCpnt: mid-level's per command structure. * * Note: potentially run from within an ISR. Must not block. **/static void sd_rw_intr(struct scsi_cmnd * SCpnt){ int result = SCpnt->result; int this_count = SCpnt->bufflen; int good_bytes = (result == 0 ? this_count : 0); sector_t block_sectors = 1; sector_t error_sector;#ifdef CONFIG_SCSI_LOGGING SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: %s: res=0x%x\n", SCpnt->request->rq_disk->disk_name, result)); if (0 != result) { SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: sb[0,2,asc,ascq]" "=%x,%x,%x,%x\n", SCpnt->sense_buffer[0], SCpnt->sense_buffer[2], SCpnt->sense_buffer[12], SCpnt->sense_buffer[13])); }#endif /* Handle MEDIUM ERRORs that indicate partial success. Since this is a relatively rare error condition, no care is taken to avoid unnecessary additional work such as memcpy's that could be avoided. */ /* An error occurred */ if (driver_byte(result) != 0 && /* An error occurred */ (SCpnt->sense_buffer[0] & 0x7f) == 0x70) { /* Sense current */ switch (SCpnt->sense_buffer[2]) { case MEDIUM_ERROR: if (!(SCpnt->sense_buffer[0] & 0x80)) break; if (!blk_fs_request(SCpnt->request)) break; error_sector = (SCpnt->sense_buffer[3] << 24) | (SCpnt->sense_buffer[4] << 16) | (SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6]; if (SCpnt->request->bio != NULL) block_sectors = bio_sectors(SCpnt->request->bio); switch (SCpnt->device->sector_size) { case 1024: error_sector <<= 1; if (block_sectors < 2) block_sectors = 2; break; case 2048: error_sector <<= 2; if (block_sectors < 4) block_sectors = 4; break; case 4096: error_sector <<=3; if (block_sectors < 8) block_sectors = 8; break; case 256: error_sector >>= 1; break; default: break; } error_sector &= ~(block_sectors - 1); good_bytes = (error_sector - SCpnt->request->sector) << 9; if (good_bytes < 0 || good_bytes >= this_count) good_bytes = 0; break; case RECOVERED_ERROR: /* an error occurred, but it recovered */ case NO_SENSE: /* LLDD got sense data */ /* * Inform the user, but make sure that it's not treated * as a hard error. */ scsi_print_sense("sd", SCpnt); SCpnt->result = 0; SCpnt->sense_buffer[0] = 0x0; good_bytes = this_count; break; case ILLEGAL_REQUEST: if (SCpnt->device->use_10_for_rw && (SCpnt->cmnd[0] == READ_10 || SCpnt->cmnd[0] == WRITE_10)) SCpnt->device->use_10_for_rw = 0; if (SCpnt->device->use_10_for_ms && (SCpnt->cmnd[0] == MODE_SENSE_10 || SCpnt->cmnd[0] == MODE_SELECT_10)) SCpnt->device->use_10_for_ms = 0; break; default: break; } } /* * This calls the generic completion function, now that we know * how many actual sectors finished, and how many sectors we need * to say have failed. */ scsi_io_completion(SCpnt, good_bytes, block_sectors << 9);}static int media_not_present(struct scsi_disk *sdkp, struct scsi_request *srp){ if (!srp->sr_result) return 0; if (!(driver_byte(srp->sr_result) & DRIVER_SENSE)) return 0; if (srp->sr_sense_buffer[2] != NOT_READY && srp->sr_sense_buffer[2] != UNIT_ATTENTION) return 0; if (srp->sr_sense_buffer[12] != 0x3A) /* medium not present */ return 0; set_media_not_present(sdkp); return 1;}/* * spinup disk - called only in sd_revalidate_disk() */static voidsd_spinup_disk(struct scsi_disk *sdkp, char *diskname, struct scsi_request *SRpnt, unsigned char *buffer) { unsigned char cmd[10]; unsigned long spintime_value = 0; int retries, spintime; unsigned int the_result; spintime = 0; /* Spin up drives, as required. Only do this at boot time */ /* Spinup needs to be done for module loads too. */ do { retries = 0; do { cmd[0] = TEST_UNIT_READY; memset((void *) &cmd[1], 0, 9); SRpnt->sr_cmd_len = 0; SRpnt->sr_sense_buffer[0] = 0; SRpnt->sr_sense_buffer[2] = 0; SRpnt->sr_data_direction = DMA_NONE; scsi_wait_req (SRpnt, (void *) cmd, (void *) buffer, 0/*512*/, SD_TIMEOUT, SD_MAX_RETRIES); the_result = SRpnt->sr_result; retries++; } while (retries < 3 && (!scsi_status_is_good(the_result) || ((driver_byte(the_result) & DRIVER_SENSE) && SRpnt->sr_sense_buffer[2] == UNIT_ATTENTION))); /* * If the drive has indicated to us that it doesn't have * any media in it, don't bother with any of the rest of * this crap. */ if (media_not_present(sdkp, SRpnt)) return; if ((driver_byte(the_result) & DRIVER_SENSE) == 0) { /* no sense, TUR either succeeded or failed * with a status error */ if(!spintime && !scsi_status_is_good(the_result)) printk(KERN_NOTICE "%s: Unit Not Ready, error = 0x%x\n", diskname, the_result); break; } /* * The device does not want the automatic start to be issued. */ if (sdkp->device->no_start_on_add) { break; } /* * If manual intervention is required, or this is an * absent USB storage device, a spinup is meaningless. */ if (SRpnt->sr_sense_buffer[2] == NOT_READY && SRpnt->sr_sense_buffer[12] == 4 /* not ready */ && SRpnt->sr_sense_buffer[13] == 3) { break; /* manual intervention required */ /* * Issue command to spin up drive when not ready */ } else if (SRpnt->sr_sense_buffer[2] == NOT_READY) { unsigned long time1; if (!spintime) { printk(KERN_NOTICE "%s: Spinning up disk...", diskname); cmd[0] = START_STOP; cmd[1] = 1; /* Return immediately */ memset((void *) &cmd[2], 0, 8); cmd[4] = 1; /* Start spin cycle */ SRpnt->sr_cmd_len = 0; SRpnt->sr_sense_buffer[0] = 0; SRpnt->sr_sense_buffer[2] = 0; SRpnt->sr_data_direction = DMA_NONE; scsi_wait_req(SRpnt, (void *)cmd, (void *) buffer, 0/*512*/, SD_TIMEOUT, SD_MAX_RETRIES); spintime_value = jiffies; } spintime = 1; time1 = HZ; /* Wait 1 second for next try */ do { current->state = TASK_UNINTERRUPTIBLE; time1 = schedule_timeout(time1); } while(time1); printk("."); } else { /* we don't understand the sense code, so it's * probably pointless to loop */ if(!spintime) { printk(KERN_NOTICE "%s: Unit Not Ready, sense:\n", diskname); scsi_print_req_sense("", SRpnt); } break; } } while (spintime && time_after(spintime_value + 100 * HZ, jiffies)); if (spintime) { if (scsi_status_is_good(the_result)) printk("ready\n"); else printk("not responding...\n"); }}/* * read disk capacity */static voidsd_read_capacity(struct scsi_disk *sdkp, char *diskname, struct scsi_request *SRpnt, unsigned char *buffer) { unsigned char cmd[16]; struct scsi_device *sdp = sdkp->device; int the_result, retries; int sector_size = 0; int longrc = 0;repeat: retries = 3; do { if (longrc) { memset((void *) cmd, 0, 16); cmd[0] = SERVICE_ACTION_IN; cmd[1] = SAI_READ_CAPACITY_16; cmd[13] = 12; memset((void *) buffer, 0, 12); } else { cmd[0] = READ_CAPACITY; memset((void *) &cmd[1], 0, 9); memset((void *) buffer, 0, 8); } SRpnt->sr_cmd_len = 0; SRpnt->sr_sense_buffer[0] = 0; SRpnt->sr_sense_buffer[2] = 0; SRpnt->sr_data_direction = DMA_FROM_DEVICE; scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer, longrc ? 12 : 8, SD_TIMEOUT, SD_MAX_RETRIES); if (media_not_present(sdkp, SRpnt)) return; the_result = SRpnt->sr_result; retries--; } while (the_result && retries); if (the_result && !longrc) { printk(KERN_NOTICE "%s : READ CAPACITY failed.\n" "%s : status=%x, message=%02x, host=%d, driver=%02x \n", diskname, diskname, status_byte(the_result), msg_byte(the_result), host_byte(the_result), driver_byte(the_result)); if (driver_byte(the_result) & DRIVER_SENSE) scsi_print_req_sense("sd", SRpnt); else printk("%s : sense not available. \n", diskname); /* Set dirty bit for removable devices if not ready - * sometimes drives will not report this properly. */ if (sdp->removable && SRpnt->sr_sense_buffer[2] == NOT_READY) sdp->changed = 1; /* Either no media are present but the drive didn't tell us, or they are present but the read capacity command fails */ /* sdkp->media_present = 0; -- not always correct */ sdkp->capacity = 0x200000; /* 1 GB - random */ return; } else if (the_result && longrc) { /* READ CAPACITY(16) has been failed */ printk(KERN_NOTICE "%s : READ CAPACITY(16) failed.\n" "%s : status=%x, message=%02x, host=%d, driver=%02x \n", diskname, diskname, status_byte(the_result), msg_byte(the_result), host_byte(the_result), driver_byte(the_result)); printk(KERN_NOTICE "%s : use 0xffffffff as device size\n", diskname); sdkp->capacity = 1 + (sector_t) 0xffffffff; goto got_data; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -