📄 sd.c
字号:
SCpnt->device->use_10_for_rw) { if (this_count > 0xffff) this_count = 0xffff; SCpnt->cmnd[0] += READ_10 - READ_6; SCpnt->cmnd[1] |= blk_fua_rq(rq) ? 0x8 : 0; SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff; SCpnt->cmnd[3] = (unsigned char) (block >> 16) & 0xff; SCpnt->cmnd[4] = (unsigned char) (block >> 8) & 0xff; SCpnt->cmnd[5] = (unsigned char) block & 0xff; SCpnt->cmnd[6] = SCpnt->cmnd[9] = 0; SCpnt->cmnd[7] = (unsigned char) (this_count >> 8) & 0xff; SCpnt->cmnd[8] = (unsigned char) this_count & 0xff; } else { if (unlikely(blk_fua_rq(rq))) { /* * This happens only if this drive failed * 10byte rw command with ILLEGAL_REQUEST * during operation and thus turned off * use_10_for_rw. */ scmd_printk(KERN_ERR, SCpnt, "FUA write on READ/WRITE(6) drive\n"); goto out; } SCpnt->cmnd[1] |= (unsigned char) ((block >> 16) & 0x1f); SCpnt->cmnd[2] = (unsigned char) ((block >> 8) & 0xff); SCpnt->cmnd[3] = (unsigned char) block & 0xff; SCpnt->cmnd[4] = (unsigned char) this_count; SCpnt->cmnd[5] = 0; } SCpnt->request_bufflen = this_count * sdp->sector_size; /* * We shouldn't disconnect in the middle of a sector, so with a dumb * host adapter, it's safe to assume that we can at least transfer * this many bytes between each connect / disconnect. */ SCpnt->transfersize = sdp->sector_size; SCpnt->underflow = this_count << 9; SCpnt->allowed = SD_MAX_RETRIES; SCpnt->timeout_per_command = timeout; /* * This indicates that the command is ready from our end to be * queued. */ ret = BLKPREP_OK; out: return scsi_prep_return(q, rq, ret);}/** * sd_open - open a scsi disk device * @inode: only i_rdev member may be used * @filp: only f_mode and f_flags may be used * * Returns 0 if successful. Returns a negated errno value in case * of error. * * Note: This can be called from a user context (e.g. fsck(1) ) * or from within the kernel (e.g. as a result of a mount(1) ). * In the latter case @inode and @filp carry an abridged amount * of information as noted above. **/static int sd_open(struct inode *inode, struct file *filp){ struct gendisk *disk = inode->i_bdev->bd_disk; struct scsi_disk *sdkp; struct scsi_device *sdev; int retval; if (!(sdkp = scsi_disk_get(disk))) return -ENXIO; SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_open\n")); sdev = sdkp->device; /* * If the device is in error recovery, wait until it is done. * If the device is offline, then disallow any access to it. */ retval = -ENXIO; if (!scsi_block_when_processing_errors(sdev)) goto error_out; if (sdev->removable || sdkp->write_prot) check_disk_change(inode->i_bdev); /* * If the drive is empty, just let the open fail. */ retval = -ENOMEDIUM; if (sdev->removable && !sdkp->media_present && !(filp->f_flags & O_NDELAY)) goto error_out; /* * If the device has the write protect tab set, have the open fail * if the user expects to be able to write to the thing. */ retval = -EROFS; if (sdkp->write_prot && (filp->f_mode & FMODE_WRITE)) goto error_out; /* * It is possible that the disk changing stuff resulted in * the device being taken offline. If this is the case, * report this to the user, and don't pretend that the * open actually succeeded. */ retval = -ENXIO; if (!scsi_device_online(sdev)) goto error_out; if (!sdkp->openers++ && sdev->removable) { if (scsi_block_when_processing_errors(sdev)) scsi_set_medium_removal(sdev, SCSI_REMOVAL_PREVENT); } return 0;error_out: scsi_disk_put(sdkp); return retval; }/** * sd_release - invoked when the (last) close(2) is called on this * scsi disk. * @inode: only i_rdev member may be used * @filp: only f_mode and f_flags may be used * * Returns 0. * * Note: may block (uninterruptible) if error recovery is underway * on this disk. **/static int sd_release(struct inode *inode, struct file *filp){ struct gendisk *disk = inode->i_bdev->bd_disk; struct scsi_disk *sdkp = scsi_disk(disk); struct scsi_device *sdev = sdkp->device; SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_release\n")); if (!--sdkp->openers && sdev->removable) { if (scsi_block_when_processing_errors(sdev)) scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW); } /* * XXX and what if there are packets in flight and this close() * XXX is followed by a "rmmod sd_mod"? */ scsi_disk_put(sdkp); return 0;}static int sd_getgeo(struct block_device *bdev, struct hd_geometry *geo){ struct scsi_disk *sdkp = scsi_disk(bdev->bd_disk); struct scsi_device *sdp = sdkp->device; struct Scsi_Host *host = sdp->host; int diskinfo[4]; /* default to most commonly used values */ diskinfo[0] = 0x40; /* 1 << 6 */ diskinfo[1] = 0x20; /* 1 << 5 */ diskinfo[2] = sdkp->capacity >> 11; /* override with calculated, extended default, or driver values */ if (host->hostt->bios_param) host->hostt->bios_param(sdp, bdev, sdkp->capacity, diskinfo); else scsicam_bios_param(bdev, sdkp->capacity, diskinfo); geo->heads = diskinfo[0]; geo->sectors = diskinfo[1]; geo->cylinders = diskinfo[2]; 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 subsystem. **/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. */ error = scsi_nonblockable_ioctl(sdp, cmd, p, filp); if (!scsi_block_when_processing_errors(sdp) || !error) return error; /* * 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->queue, 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, sd_printk(KERN_INFO, sdkp, "sd_media_changed\n")); 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_disk *sdkp){ int retries, res; struct scsi_device *sdp = sdkp->device; struct scsi_sense_hdr sshdr; if (!scsi_device_online(sdp)) return -ENODEV; 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. */ res = scsi_execute_req(sdp, cmd, DMA_NONE, NULL, 0, &sshdr, SD_TIMEOUT, SD_MAX_RETRIES); if (res == 0) break; } if (res) { sd_print_result(sdkp, res); if (driver_byte(res) & DRIVER_SENSE) sd_print_sense_hdr(sdkp, &sshdr); } if (res) return -EIO; return 0;}static void sd_prepare_flush(struct request_queue *q, struct request *rq){ memset(rq->cmd, 0, sizeof(rq->cmd)); rq->cmd_type = REQ_TYPE_BLOCK_PC; rq->timeout = SD_TIMEOUT; rq->cmd[0] = SYNCHRONIZE_CACHE; rq->cmd_len = 10;}static void sd_rescan(struct device *dev){ struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev); if (sdkp) { sd_revalidate_disk(sdkp->disk); scsi_disk_put(sdkp); }}#ifdef CONFIG_COMPAT/* * This gets directly called from VFS. When the ioctl * is not recognized we go back to the other translation paths. */static long sd_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg){ struct block_device *bdev = file->f_path.dentry->d_inode->i_bdev; struct gendisk *disk = bdev->bd_disk; struct scsi_device *sdev = scsi_disk(disk)->device; /* * 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(sdev)) return -ENODEV; if (sdev->host->hostt->compat_ioctl) { int ret; ret = sdev->host->hostt->compat_ioctl(sdev, cmd, (void __user *)arg); return ret; } /* * Let the static ioctl translation table take care of it. */ return -ENOIOCTLCMD; }#endifstatic struct block_device_operations sd_fops = { .owner = THIS_MODULE, .open = sd_open, .release = sd_release, .ioctl = sd_ioctl, .getgeo = sd_getgeo,#ifdef CONFIG_COMPAT .compat_ioctl = sd_compat_ioctl,#endif .media_changed = sd_media_changed, .revalidate_disk = sd_revalidate_disk,};/** * sd_done - 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 int sd_done(struct scsi_cmnd *SCpnt){ int result = SCpnt->result; unsigned int xfer_size = SCpnt->request_bufflen; unsigned int good_bytes = result ? 0 : xfer_size; u64 start_lba = SCpnt->request->sector; u64 bad_lba; struct scsi_sense_hdr sshdr; int sense_valid = 0; int sense_deferred = 0; int info_valid; if (result) { sense_valid = scsi_command_normalize_sense(SCpnt, &sshdr); if (sense_valid) sense_deferred = scsi_sense_is_deferred(&sshdr); }#ifdef CONFIG_SCSI_LOGGING SCSI_LOG_HLCOMPLETE(1, scsi_print_result(SCpnt)); if (sense_valid) { SCSI_LOG_HLCOMPLETE(1, scmd_printk(KERN_INFO, SCpnt, "sd_done: sb[respc,sk,asc," "ascq]=%x,%x,%x,%x\n", sshdr.response_code, sshdr.sense_key, sshdr.asc, sshdr.ascq)); }#endif if (driver_byte(result) != DRIVER_SENSE && (!sense_valid || sense_deferred)) goto out; switch (sshdr.sense_key) { case HARDWARE_ERROR: case MEDIUM_ERROR: if (!blk_fs_request(SCpnt->request)) goto out; info_valid = scsi_get_sense_info_fld(SCpnt->sense_buffer, SCSI_SENSE_BUFFERSIZE, &bad_lba); if (!info_valid) goto out; if (xfer_size <= SCpnt->device->sector_size) goto out; switch (SCpnt->device->sector_size) { case 256: start_lba <<= 1; break; case 512: break; case 1024: start_lba >>= 1; break; case 2048: start_lba >>= 2; break; case 4096:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -