sd.c
字号:
if (!longrc) { sector_size = (buffer[4] << 24) | (buffer[5] << 16) | (buffer[6] << 8) | buffer[7]; if (buffer[0] == 0xff && buffer[1] == 0xff && buffer[2] == 0xff && buffer[3] == 0xff) { if(sizeof(sdkp->capacity) > 4) { printk(KERN_NOTICE "%s : very big device. try to use" " READ CAPACITY(16).\n", diskname); longrc = 1; goto repeat; } else { printk(KERN_ERR "%s: too big for kernel. Assuming maximum 2Tb\n", diskname); } } sdkp->capacity = 1 + (((sector_t)buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]); } else { sdkp->capacity = 1 + (((u64)buffer[0] << 56) | ((u64)buffer[1] << 48) | ((u64)buffer[2] << 40) | ((u64)buffer[3] << 32) | ((sector_t)buffer[4] << 24) | ((sector_t)buffer[5] << 16) | ((sector_t)buffer[6] << 8) | (sector_t)buffer[7]); sector_size = (buffer[8] << 24) | (buffer[9] << 16) | (buffer[10] << 8) | buffer[11]; } got_data: if (sector_size == 0) { sector_size = 512; printk(KERN_NOTICE "%s : sector size 0 reported, " "assuming 512.\n", diskname); } if (sector_size != 512 && sector_size != 1024 && sector_size != 2048 && sector_size != 4096 && sector_size != 256) { printk(KERN_NOTICE "%s : unsupported sector size " "%d.\n", diskname, sector_size); /* * The user might want to re-format the drive with * a supported sectorsize. Once this happens, it * would be relatively trivial to set the thing up. * For this reason, we leave the thing in the table. */ sdkp->capacity = 0; } { /* * The msdos fs needs to know the hardware sector size * So I have created this table. See ll_rw_blk.c * Jacques Gelinas (Jacques@solucorp.qc.ca) */ int hard_sector = sector_size; sector_t sz = sdkp->capacity * (hard_sector/256); request_queue_t *queue = sdp->request_queue; sector_t mb; blk_queue_hardsect_size(queue, hard_sector); /* avoid 64-bit division on 32-bit platforms */ mb = sz >> 1; sector_div(sz, 1250); mb -= sz - 974; sector_div(mb, 1950); printk(KERN_NOTICE "SCSI device %s: " "%llu %d-byte hdwr sectors (%llu MB)\n", diskname, (unsigned long long)sdkp->capacity, hard_sector, (unsigned long long)mb); } /* Rescale capacity to 512-byte units */ if (sector_size == 4096) sdkp->capacity <<= 3; else if (sector_size == 2048) sdkp->capacity <<= 2; else if (sector_size == 1024) sdkp->capacity <<= 1; else if (sector_size == 256) sdkp->capacity >>= 1; sdkp->device->sector_size = sector_size;}/* called with buffer of length 512 */static inline intsd_do_mode_sense(struct scsi_request *SRpnt, int dbd, int modepage, unsigned char *buffer, int len, struct scsi_mode_data *data){ return __scsi_mode_sense(SRpnt, dbd, modepage, buffer, len, SD_TIMEOUT, SD_MAX_RETRIES, data);}/* * read write protect setting, if possible - called only in sd_revalidate_disk() * called with buffer of length 512 */static voidsd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname, struct scsi_request *SRpnt, unsigned char *buffer) { int res; struct scsi_mode_data data; set_disk_ro(sdkp->disk, 0); if (sdkp->device->skip_ms_page_3f) { printk(KERN_NOTICE "%s: assuming Write Enabled\n", diskname); return; } if (sdkp->device->use_192_bytes_for_3f) { res = sd_do_mode_sense(SRpnt, 0, 0x3F, buffer, 192, &data); } else { /* * First attempt: ask for all pages (0x3F), but only 4 bytes. * We have to start carefully: some devices hang if we ask * for more than is available. */ res = sd_do_mode_sense(SRpnt, 0, 0x3F, buffer, 4, &data); /* * Second attempt: ask for page 0 When only page 0 is * implemented, a request for page 3F may return Sense Key * 5: Illegal Request, Sense Code 24: Invalid field in * CDB. */ if (!scsi_status_is_good(res)) res = sd_do_mode_sense(SRpnt, 0, 0, buffer, 4, &data); /* * Third attempt: ask 255 bytes, as we did earlier. */ if (!scsi_status_is_good(res)) res = sd_do_mode_sense(SRpnt, 0, 0x3F, buffer, 255, &data); } if (!scsi_status_is_good(res)) { printk(KERN_WARNING "%s: test WP failed, assume Write Enabled\n", diskname); } else { sdkp->write_prot = ((data.device_specific & 0x80) != 0); set_disk_ro(sdkp->disk, sdkp->write_prot); printk(KERN_NOTICE "%s: Write Protect is %s\n", diskname, sdkp->write_prot ? "on" : "off"); printk(KERN_DEBUG "%s: Mode Sense: %02x %02x %02x %02x\n", diskname, buffer[0], buffer[1], buffer[2], buffer[3]); }}/* * sd_read_cache_type - called only from sd_revalidate_disk() * called with buffer of length 512 */static voidsd_read_cache_type(struct scsi_disk *sdkp, char *diskname, struct scsi_request *SRpnt, unsigned char *buffer) { int len = 0, res; const int dbd = 0; /* DBD */ const int modepage = 0x08; /* current values, cache page */ struct scsi_mode_data data; if (sdkp->device->skip_ms_page_8) goto defaults; /* cautiously ask */ res = sd_do_mode_sense(SRpnt, dbd, modepage, buffer, 4, &data); if (!scsi_status_is_good(res)) goto bad_sense; /* that went OK, now ask for the proper length */ len = data.length; /* * We're only interested in the first three bytes, actually. * But the data cache page is defined for the first 20. */ 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; /* Get the data */ res = sd_do_mode_sense(SRpnt, dbd, modepage, buffer, len, &data); if (scsi_status_is_good(res)) { const char *types[] = { "write through", "none", "write back", "write back, no read (daft)" }; int ct = 0; int offset = data.header_length + data.block_descriptor_length + 2; sdkp->WCE = ((buffer[offset] & 0x04) != 0); sdkp->RCD = ((buffer[offset] & 0x01) != 0); ct = sdkp->RCD + 2*sdkp->WCE; printk(KERN_NOTICE "SCSI device %s: drive cache: %s\n", diskname, types[ct]); return; }bad_sense: if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 && (SRpnt->sr_sense_buffer[2] & 0x0f) == ILLEGAL_REQUEST /* ASC 0x24 ASCQ 0x00: Invalid field in CDB */ && SRpnt->sr_sense_buffer[12] == 0x24 && SRpnt->sr_sense_buffer[13] == 0x00) { printk(KERN_NOTICE "%s: cache data unavailable\n", diskname); } else { printk(KERN_ERR "%s: asking for cache data failed\n", diskname); }defaults: printk(KERN_ERR "%s: assuming drive cache: write through\n", diskname); sdkp->WCE = 0; sdkp->RCD = 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; struct scsi_request *sreq; unsigned char *buffer; SCSI_LOG_HLQUEUE(3, printk("sd_revalidate_disk: disk=%s\n", disk->disk_name)); /* * If the device is offline, don't try and read capacity or any * of the other niceties. */ if (!scsi_device_online(sdp)) goto out; sreq = scsi_allocate_request(sdp, GFP_KERNEL); if (!sreq) { printk(KERN_WARNING "(sd_revalidate_disk:) Request allocation " "failure.\n"); goto out; } buffer = kmalloc(512, GFP_KERNEL | __GFP_DMA); if (!buffer) { printk(KERN_WARNING "(sd_revalidate_disk:) Memory allocation " "failure.\n"); goto out_release_request; } /* 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, disk->disk_name, sreq, buffer); /* * Without media there is no reason to ask; moreover, some devices * react badly if we do. */ if (sdkp->media_present) { sd_read_capacity(sdkp, disk->disk_name, sreq, buffer); if (sdp->removable) sd_read_write_protect_flag(sdkp, disk->disk_name, sreq, buffer); sd_read_cache_type(sdkp, disk->disk_name, sreq, buffer); } set_capacity(disk, sdkp->capacity); kfree(buffer); out_release_request: scsi_release_request(sreq); 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)) goto out; SCSI_LOG_HLQUEUE(3, printk("sd_attach: scsi device: <%d,%d,%d,%d>\n", sdp->host->host_no, sdp->channel, sdp->id, sdp->lun)); error = -ENOMEM; sdkp = kmalloc(sizeof(*sdkp), GFP_KERNEL); if (!sdkp) goto out; memset (sdkp, 0, sizeof(*sdkp)); kref_init(&sdkp->kref); 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_DISK) sdp->timeout = SD_TIMEOUT; else sdp->timeout = SD_MOD_TIMEOUT; } 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); } strcpy(gd->devfs_name, sdp->devfs_name); gd->private_data = &sdkp->driver; sd_revalidate_disk(gd); gd->driverfs_dev = &sdp->sdev_gendev; gd->flags = GENHD_FL_DRIVERFS; if (sdp->removable) gd->flags |= GENHD_FL_REMOVABLE; gd->queue = sdkp->device->request_queue; dev_set_drvdata(dev, sdkp); add_disk(gd); printk(KERN_NOTICE "Attached scsi %sdisk %s at scsi%d, channel %d, " "id %d, lun %d\n", sdp->removable ? "removable " : "", gd->disk_name, sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 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); del_gendisk(sdkp->disk); sd_shutdown(dev); down(&sd_ref_sem); kref_put(&sdkp->kref, scsi_disk_release); up(&sd_ref_sem); return 0;}/** * scsi_disk_release - Called to free the scsi_disk structure * @kref: pointer to embedded kref * * sd_ref_sem 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 kref_put(). **/static void scsi_disk_release(struct kref *kref){ struct scsi_disk *sdkp = to_scsi_disk(kref); 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); kfree(sdkp);}/* * 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_device *sdp = to_scsi_device(dev); struct scsi_disk *sdkp = dev_get_drvdata(dev); if (!sdkp) return; /* this can happen */ if (!sdkp->WCE) return; printk(KERN_NOTICE "Synchronizing SCSI cache for disk %s: \n", sdkp->disk->disk_name); sd_sync_cache(sdp);} /** * 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; 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; return scsi_register_driver(&sd_template.gendrv);}/** * 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); for (i = 0; i < SD_MAJORS; i++) unregister_blkdev(sd_major(i), "sd");}MODULE_LICENSE("GPL");MODULE_AUTHOR("Eric Youngdale");MODULE_DESCRIPTION("SCSI disk (sd) driver");module_init(init_sd);module_exit(exit_sd);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -