📄 sd.c
字号:
if (len < 3) goto bad_sense; if (len > 20) len = 20; /* Take headers and block descriptors into account */ len += data.header_length + data.block_descriptor_length; if (len > SD_BUF_SIZE) goto bad_sense; /* Get the data */ res = sd_do_mode_sense(sdp, dbd, modepage, buffer, len, &data, &sshdr); if (scsi_status_is_good(res)) { int offset = data.header_length + data.block_descriptor_length; if (offset >= SD_BUF_SIZE - 2) { sd_printk(KERN_ERR, sdkp, "Malformed MODE SENSE response\n"); goto defaults; } if ((buffer[offset] & 0x3f) != modepage) { sd_printk(KERN_ERR, sdkp, "Got wrong page\n"); goto defaults; } if (modepage == 8) { sdkp->WCE = ((buffer[offset + 2] & 0x04) != 0); sdkp->RCD = ((buffer[offset + 2] & 0x01) != 0); } else { sdkp->WCE = ((buffer[offset + 2] & 0x01) == 0); sdkp->RCD = 0; } sdkp->DPOFUA = (data.device_specific & 0x10) != 0; if (sdkp->DPOFUA && !sdkp->device->use_10_for_rw) { sd_printk(KERN_NOTICE, sdkp, "Uses READ/WRITE(6), disabling FUA\n"); sdkp->DPOFUA = 0; } sd_printk(KERN_NOTICE, sdkp, "Write cache: %s, read cache: %s, %s\n", sdkp->WCE ? "enabled" : "disabled", sdkp->RCD ? "disabled" : "enabled", sdkp->DPOFUA ? "supports DPO and FUA" : "doesn't support DPO or FUA"); return; }bad_sense: if (scsi_sense_valid(&sshdr) && sshdr.sense_key == ILLEGAL_REQUEST && sshdr.asc == 0x24 && sshdr.ascq == 0x0) /* Invalid field in CDB */ sd_printk(KERN_NOTICE, sdkp, "Cache data unavailable\n"); else sd_printk(KERN_ERR, sdkp, "Asking for cache data failed\n");defaults: sd_printk(KERN_ERR, sdkp, "Assuming drive cache: write through\n"); sdkp->WCE = 0; sdkp->RCD = 0; sdkp->DPOFUA = 0;}/** * sd_revalidate_disk - called the first time a new disk is seen, * performs disk spin up, read_capacity, etc. * @disk: struct gendisk we care about **/static int sd_revalidate_disk(struct gendisk *disk){ struct scsi_disk *sdkp = scsi_disk(disk); struct scsi_device *sdp = sdkp->device; unsigned char *buffer; unsigned ordered; SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_revalidate_disk\n")); /* * If the device is offline, don't try and read capacity or any * of the other niceties. */ if (!scsi_device_online(sdp)) goto out; buffer = kmalloc(SD_BUF_SIZE, GFP_KERNEL); if (!buffer) { sd_printk(KERN_WARNING, sdkp, "sd_revalidate_disk: Memory " "allocation failure.\n"); goto out; } /* defaults, until the device tells us otherwise */ sdp->sector_size = 512; sdkp->capacity = 0; sdkp->media_present = 1; sdkp->write_prot = 0; sdkp->WCE = 0; sdkp->RCD = 0; sd_spinup_disk(sdkp); /* * Without media there is no reason to ask; moreover, some devices * react badly if we do. */ if (sdkp->media_present) { sd_read_capacity(sdkp, buffer); sd_read_write_protect_flag(sdkp, buffer); sd_read_cache_type(sdkp, buffer); } /* * We now have all cache related info, determine how we deal * with ordered requests. Note that as the current SCSI * dispatch function can alter request order, we cannot use * QUEUE_ORDERED_TAG_* even when ordered tag is supported. */ if (sdkp->WCE) ordered = sdkp->DPOFUA ? QUEUE_ORDERED_DRAIN_FUA : QUEUE_ORDERED_DRAIN_FLUSH; else ordered = QUEUE_ORDERED_DRAIN; blk_queue_ordered(sdkp->disk->queue, ordered, sd_prepare_flush); set_capacity(disk, sdkp->capacity); kfree(buffer); out: return 0;}/** * sd_probe - called during driver initialization and whenever a * new scsi device is attached to the system. It is called once * for each scsi device (not just disks) present. * @dev: pointer to device object * * Returns 0 if successful (or not interested in this scsi device * (e.g. scanner)); 1 when there is an error. * * Note: this function is invoked from the scsi mid-level. * This function sets up the mapping between a given * <host,channel,id,lun> (found in sdp) and new device name * (e.g. /dev/sda). More precisely it is the block device major * and minor number that is chosen here. * * Assume sd_attach is not re-entrant (for time being) * Also think about sd_attach() and sd_remove() running coincidentally. **/static int sd_probe(struct device *dev){ struct scsi_device *sdp = to_scsi_device(dev); struct scsi_disk *sdkp; struct gendisk *gd; u32 index; int error; error = -ENODEV; if (sdp->type != TYPE_DISK && sdp->type != TYPE_MOD && sdp->type != TYPE_RBC) goto out; SCSI_LOG_HLQUEUE(3, sdev_printk(KERN_INFO, sdp, "sd_attach\n")); error = -ENOMEM; sdkp = kzalloc(sizeof(*sdkp), GFP_KERNEL); if (!sdkp) goto out; gd = alloc_disk(16); if (!gd) goto out_free; if (!idr_pre_get(&sd_index_idr, GFP_KERNEL)) goto out_put; spin_lock(&sd_index_lock); error = idr_get_new(&sd_index_idr, NULL, &index); spin_unlock(&sd_index_lock); if (index >= SD_MAX_DISKS) error = -EBUSY; if (error) goto out_put; sdkp->device = sdp; sdkp->driver = &sd_template; sdkp->disk = gd; sdkp->index = index; sdkp->openers = 0; if (!sdp->timeout) { if (sdp->type != TYPE_MOD) sdp->timeout = SD_TIMEOUT; else sdp->timeout = SD_MOD_TIMEOUT; } class_device_initialize(&sdkp->cdev); sdkp->cdev.dev = &sdp->sdev_gendev; sdkp->cdev.class = &sd_disk_class; strncpy(sdkp->cdev.class_id, sdp->sdev_gendev.bus_id, BUS_ID_SIZE); if (class_device_add(&sdkp->cdev)) goto out_put; get_device(&sdp->sdev_gendev); gd->major = sd_major((index & 0xf0) >> 4); gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00); gd->minors = 16; gd->fops = &sd_fops; if (index < 26) { sprintf(gd->disk_name, "sd%c", 'a' + index % 26); } else if (index < (26 + 1) * 26) { sprintf(gd->disk_name, "sd%c%c", 'a' + index / 26 - 1,'a' + index % 26); } else { const unsigned int m1 = (index / 26 - 1) / 26 - 1; const unsigned int m2 = (index / 26 - 1) % 26; const unsigned int m3 = index % 26; sprintf(gd->disk_name, "sd%c%c%c", 'a' + m1, 'a' + m2, 'a' + m3); } gd->private_data = &sdkp->driver; gd->queue = sdkp->device->request_queue; sd_revalidate_disk(gd); blk_queue_prep_rq(sdp->request_queue, sd_prep_fn); gd->driverfs_dev = &sdp->sdev_gendev; gd->flags = GENHD_FL_DRIVERFS; if (sdp->removable) gd->flags |= GENHD_FL_REMOVABLE; dev_set_drvdata(dev, sdkp); add_disk(gd); sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n", sdp->removable ? "removable " : ""); return 0; out_put: put_disk(gd); out_free: kfree(sdkp); out: return error;}/** * sd_remove - called whenever a scsi disk (previously recognized by * sd_probe) is detached from the system. It is called (potentially * multiple times) during sd module unload. * @sdp: pointer to mid level scsi device object * * Note: this function is invoked from the scsi mid-level. * This function potentially frees up a device name (e.g. /dev/sdc) * that could be re-used by a subsequent sd_probe(). * This function is not called when the built-in sd driver is "exit-ed". **/static int sd_remove(struct device *dev){ struct scsi_disk *sdkp = dev_get_drvdata(dev); class_device_del(&sdkp->cdev); del_gendisk(sdkp->disk); sd_shutdown(dev); mutex_lock(&sd_ref_mutex); dev_set_drvdata(dev, NULL); class_device_put(&sdkp->cdev); mutex_unlock(&sd_ref_mutex); return 0;}/** * scsi_disk_release - Called to free the scsi_disk structure * @cdev: pointer to embedded class device * * sd_ref_mutex must be held entering this routine. Because it is * called on last put, you should always use the scsi_disk_get() * scsi_disk_put() helpers which manipulate the semaphore directly * and never do a direct class_device_put(). **/static void scsi_disk_release(struct class_device *cdev){ struct scsi_disk *sdkp = to_scsi_disk(cdev); struct gendisk *disk = sdkp->disk; spin_lock(&sd_index_lock); idr_remove(&sd_index_idr, sdkp->index); spin_unlock(&sd_index_lock); disk->private_data = NULL; put_disk(disk); put_device(&sdkp->device->sdev_gendev); kfree(sdkp);}static int sd_start_stop_device(struct scsi_disk *sdkp, int start){ unsigned char cmd[6] = { START_STOP }; /* START_VALID */ struct scsi_sense_hdr sshdr; struct scsi_device *sdp = sdkp->device; int res; if (start) cmd[4] |= 1; /* START */ if (!scsi_device_online(sdp)) return -ENODEV; res = scsi_execute_req(sdp, cmd, DMA_NONE, NULL, 0, &sshdr, SD_TIMEOUT, SD_MAX_RETRIES); if (res) { sd_printk(KERN_WARNING, sdkp, "START_STOP FAILED\n"); sd_print_result(sdkp, res); if (driver_byte(res) & DRIVER_SENSE) sd_print_sense_hdr(sdkp, &sshdr); } return res;}/* * Send a SYNCHRONIZE CACHE instruction down to the device through * the normal SCSI command structure. Wait for the command to * complete. */static void sd_shutdown(struct device *dev){ struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev); if (!sdkp) return; /* this can happen */ if (sdkp->WCE) { sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n"); sd_sync_cache(sdkp); } if (system_state != SYSTEM_RESTART && sdkp->device->manage_start_stop) { sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n"); sd_start_stop_device(sdkp, 0); } scsi_disk_put(sdkp);}static int sd_suspend(struct device *dev, pm_message_t mesg){ struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev); int ret = 0; if (!sdkp) return 0; /* this can happen */ if (sdkp->WCE) { sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n"); ret = sd_sync_cache(sdkp); if (ret) goto done; } if (mesg.event == PM_EVENT_SUSPEND && sdkp->device->manage_start_stop) { sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n"); ret = sd_start_stop_device(sdkp, 0); }done: scsi_disk_put(sdkp); return ret;}static int sd_resume(struct device *dev){ struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev); int ret = 0; if (!sdkp->device->manage_start_stop) goto done; sd_printk(KERN_NOTICE, sdkp, "Starting disk\n"); ret = sd_start_stop_device(sdkp, 1);done: scsi_disk_put(sdkp); return ret;}/** * init_sd - entry point for this driver (both when built in or when * a module). * * Note: this function registers this driver with the scsi mid-level. **/static int __init init_sd(void){ int majors = 0, i, err; SCSI_LOG_HLQUEUE(3, printk("init_sd: sd driver entry point\n")); for (i = 0; i < SD_MAJORS; i++) if (register_blkdev(sd_major(i), "sd") == 0) majors++; if (!majors) return -ENODEV; err = class_register(&sd_disk_class); if (err) goto err_out; err = scsi_register_driver(&sd_template.gendrv); if (err) goto err_out_class; return 0;err_out_class: class_unregister(&sd_disk_class);err_out: for (i = 0; i < SD_MAJORS; i++) unregister_blkdev(sd_major(i), "sd"); return err;}/** * exit_sd - exit point for this driver (when it is a module). * * Note: this function unregisters this driver from the scsi mid-level. **/static void __exit exit_sd(void){ int i; SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n")); scsi_unregister_driver(&sd_template.gendrv); class_unregister(&sd_disk_class); for (i = 0; i < SD_MAJORS; i++) unregister_blkdev(sd_major(i), "sd");}module_init(init_sd);module_exit(exit_sd);static void sd_print_sense_hdr(struct scsi_disk *sdkp, struct scsi_sense_hdr *sshdr){ sd_printk(KERN_INFO, sdkp, ""); scsi_show_sense_hdr(sshdr); sd_printk(KERN_INFO, sdkp, ""); scsi_show_extd_sense(sshdr->asc, sshdr->ascq);}static void sd_print_result(struct scsi_disk *sdkp, int result){ sd_printk(KERN_INFO, sdkp, ""); scsi_show_result(result);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -