⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sd.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	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 + -