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

📄 ub.c

📁 Linux块设备驱动源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	scmd = &sc->top_rqs_cmd;	memset(scmd, 0, sizeof(struct ub_scsi_cmd));	scmd->cdb[0] = REQUEST_SENSE;	scmd->cdb[4] = UB_SENSE_SIZE;	scmd->cdb_len = 6;	scmd->dir = UB_DIR_READ;	scmd->state = UB_CMDST_INIT;	scmd->nsg = 1;	sg = &scmd->sgv[0];	sg->page = virt_to_page(sc->top_sense);	sg->offset = (unsigned int)sc->top_sense & (PAGE_SIZE-1);	sg->length = UB_SENSE_SIZE;	scmd->len = UB_SENSE_SIZE;	scmd->lun = cmd->lun;	scmd->done = ub_top_sense_done;	scmd->back = cmd;	scmd->tag = sc->tagcnt++;	cmd->state = UB_CMDST_SENSE;	ub_cmdtr_state(sc, cmd);	ub_cmdq_insert(sc, scmd);	return;error:	ub_state_done(sc, cmd, rc);}/* * A helper for the command's state machine: * Submit a stall clear. */static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd,    int stalled_pipe){	int endp;	struct usb_ctrlrequest *cr;	int rc;	endp = usb_pipeendpoint(stalled_pipe);	if (usb_pipein (stalled_pipe))		endp |= USB_DIR_IN;	cr = &sc->work_cr;	cr->bRequestType = USB_RECIP_ENDPOINT;	cr->bRequest = USB_REQ_CLEAR_FEATURE;	cr->wValue = cpu_to_le16(USB_ENDPOINT_HALT);	cr->wIndex = cpu_to_le16(endp);	cr->wLength = cpu_to_le16(0);	UB_INIT_COMPLETION(sc->work_done);	usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,	    (unsigned char*) cr, NULL, 0, ub_urb_complete, sc);	sc->work_urb.actual_length = 0;	sc->work_urb.error_count = 0;	sc->work_urb.status = 0;	if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) {		ub_complete(&sc->work_done);		return rc;	}	sc->work_timer.expires = jiffies + UB_CTRL_TIMEOUT;	add_timer(&sc->work_timer);	return 0;}/* */static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd){	unsigned char *sense = sc->top_sense;	struct ub_scsi_cmd *cmd;	/*	 * Ignoring scmd->act_len, because the buffer was pre-zeroed.	 */	ub_cmdtr_sense(sc, scmd, sense);	/*	 * Find the command which triggered the unit attention or a check,	 * save the sense into it, and advance its state machine.	 */	if ((cmd = ub_cmdq_peek(sc)) == NULL) {		printk(KERN_WARNING "%s: sense done while idle\n", sc->name);		return;	}	if (cmd != scmd->back) {		printk(KERN_WARNING "%s: "		    "sense done for wrong command 0x%x\n",		    sc->name, cmd->tag);		return;	}	if (cmd->state != UB_CMDST_SENSE) {		printk(KERN_WARNING "%s: "		    "sense done with bad cmd state %d\n",		    sc->name, cmd->state);		return;	}	cmd->key = sense[2] & 0x0F;	cmd->asc = sense[12];	cmd->ascq = sense[13];	ub_scsi_urb_compl(sc, cmd);}/* * This is called from a process context. */static void ub_revalidate(struct ub_dev *sc, struct ub_lun *lun){	lun->readonly = 0;	/* XXX Query this from the device */	lun->capacity.nsec = 0;	lun->capacity.bsize = 512;	lun->capacity.bshift = 0;	if (ub_sync_tur(sc, lun) != 0)		return;			/* Not ready */	lun->changed = 0;	if (ub_sync_read_cap(sc, lun, &lun->capacity) != 0) {		/*		 * The retry here means something is wrong, either with the		 * device, with the transport, or with our code.		 * We keep this because sd.c has retries for capacity.		 */		if (ub_sync_read_cap(sc, lun, &lun->capacity) != 0) {			lun->capacity.nsec = 0;			lun->capacity.bsize = 512;			lun->capacity.bshift = 0;		}	}}/* * The open funcion. * This is mostly needed to keep refcounting, but also to support * media checks on removable media drives. */static int ub_bd_open(struct inode *inode, struct file *filp){	struct gendisk *disk = inode->i_bdev->bd_disk;	struct ub_lun *lun;	struct ub_dev *sc;	unsigned long flags;	int rc;	if ((lun = disk->private_data) == NULL)		return -ENXIO;	sc = lun->udev;	spin_lock_irqsave(&ub_lock, flags);	if (atomic_read(&sc->poison)) {		spin_unlock_irqrestore(&ub_lock, flags);		return -ENXIO;	}	sc->openc++;	spin_unlock_irqrestore(&ub_lock, flags);	/*	 * This is a workaround for a specific problem in our block layer.	 * In 2.6.9, register_disk duplicates the code from rescan_partitions.	 * However, if we do add_disk with a device which persistently reports	 * a changed media, add_disk calls register_disk, which does do_open,	 * which will call rescan_paritions for changed media. After that,	 * register_disk attempts to do it all again and causes double kobject	 * registration and a eventually an oops on module removal.	 *	 * The bottom line is, Al Viro says that we should not allow	 * bdev->bd_invalidated to be set when doing add_disk no matter what.	 */	if (lun->first_open) {		lun->first_open = 0;		if (lun->changed) {			rc = -ENOMEDIUM;			goto err_open;		}	}	if (lun->removable || lun->readonly)		check_disk_change(inode->i_bdev);	/*	 * The sd.c considers ->media_present and ->changed not equivalent,	 * under some pretty murky conditions (a failure of READ CAPACITY).	 * We may need it one day.	 */	if (lun->removable && lun->changed && !(filp->f_flags & O_NDELAY)) {		rc = -ENOMEDIUM;		goto err_open;	}	if (lun->readonly && (filp->f_mode & FMODE_WRITE)) {		rc = -EROFS;		goto err_open;	}	return 0;err_open:	ub_put(sc);	return rc;}/* */static int ub_bd_release(struct inode *inode, struct file *filp){	struct gendisk *disk = inode->i_bdev->bd_disk;	struct ub_lun *lun = disk->private_data;	struct ub_dev *sc = lun->udev;	ub_put(sc);	return 0;}/* * The ioctl interface. */static int ub_bd_ioctl(struct inode *inode, struct file *filp,    unsigned int cmd, unsigned long arg){	struct gendisk *disk = inode->i_bdev->bd_disk;	void __user *usermem = (void __user *) arg;	return scsi_cmd_ioctl(filp, disk, cmd, usermem);}/* * This is called once a new disk was seen by the block layer or by ub_probe(). * The main onjective here is to discover the features of the media such as * the capacity, read-only status, etc. USB storage generally does not * need to be spun up, but if we needed it, this would be the place. * * This call can sleep. * * The return code is not used. */static int ub_bd_revalidate(struct gendisk *disk){	struct ub_lun *lun = disk->private_data;	ub_revalidate(lun->udev, lun);	/* XXX Support sector size switching like in sr.c */	blk_queue_hardsect_size(disk->queue, lun->capacity.bsize);	set_capacity(disk, lun->capacity.nsec);	// set_disk_ro(sdkp->disk, lun->readonly);	return 0;}/* * The check is called by the block layer to verify if the media * is still available. It is supposed to be harmless, lightweight and * non-intrusive in case the media was not changed. * * This call can sleep. * * The return code is bool! */static int ub_bd_media_changed(struct gendisk *disk){	struct ub_lun *lun = disk->private_data;	if (!lun->removable)		return 0;	/*	 * We clean checks always after every command, so this is not	 * as dangerous as it looks. If the TEST_UNIT_READY fails here,	 * the device is actually not ready with operator or software	 * intervention required. One dangerous item might be a drive which	 * spins itself down, and come the time to write dirty pages, this	 * will fail, then block layer discards the data. Since we never	 * spin drives up, such devices simply cannot be used with ub anyway.	 */	if (ub_sync_tur(lun->udev, lun) != 0) {		lun->changed = 1;		return 1;	}	return lun->changed;}static struct block_device_operations ub_bd_fops = {	.owner		= THIS_MODULE,	.open		= ub_bd_open,	.release	= ub_bd_release,	.ioctl		= ub_bd_ioctl,	.media_changed	= ub_bd_media_changed,	.revalidate_disk = ub_bd_revalidate,};/* * Common ->done routine for commands executed synchronously. */static void ub_probe_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd){	struct completion *cop = cmd->back;	complete(cop);}/* * Test if the device has a check condition on it, synchronously. */static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun){	struct ub_scsi_cmd *cmd;	enum { ALLOC_SIZE = sizeof(struct ub_scsi_cmd) };	unsigned long flags;	struct completion compl;	int rc;	init_completion(&compl);	rc = -ENOMEM;	if ((cmd = kmalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)		goto err_alloc;	memset(cmd, 0, ALLOC_SIZE);	cmd->cdb[0] = TEST_UNIT_READY;	cmd->cdb_len = 6;	cmd->dir = UB_DIR_NONE;	cmd->state = UB_CMDST_INIT;	cmd->lun = lun;			/* This may be NULL, but that's ok */	cmd->done = ub_probe_done;	cmd->back = &compl;	spin_lock_irqsave(&sc->lock, flags);	cmd->tag = sc->tagcnt++;	rc = ub_submit_scsi(sc, cmd);	spin_unlock_irqrestore(&sc->lock, flags);	if (rc != 0) {		printk("ub: testing ready: submit error (%d)\n", rc); /* P3 */		goto err_submit;	}	wait_for_completion(&compl);	rc = cmd->error;	if (rc == -EIO && cmd->key != 0)	/* Retries for benh's key */		rc = cmd->key;err_submit:	kfree(cmd);err_alloc:	return rc;}/* * Read the SCSI capacity synchronously (for probing). */static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,    struct ub_capacity *ret){	struct ub_scsi_cmd *cmd;	struct scatterlist *sg;	char *p;	enum { ALLOC_SIZE = sizeof(struct ub_scsi_cmd) + 8 };	unsigned long flags;	unsigned int bsize, shift;	unsigned long nsec;	struct completion compl;	int rc;	init_completion(&compl);	rc = -ENOMEM;	if ((cmd = kmalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)		goto err_alloc;	memset(cmd, 0, ALLOC_SIZE);	p = (char *)cmd + sizeof(struct ub_scsi_cmd);	cmd->cdb[0] = 0x25;	cmd->cdb_len = 10;	cmd->dir = UB_DIR_READ;	cmd->state = UB_CMDST_INIT;	cmd->nsg = 1;	sg = &cmd->sgv[0];	sg->page = virt_to_page(p);	sg->offset = (unsigned int)p & (PAGE_SIZE-1);	sg->length = 8;	cmd->len = 8;	cmd->lun = lun;	cmd->done = ub_probe_done;	cmd->back = &compl;	spin_lock_irqsave(&sc->lock, flags);	cmd->tag = sc->tagcnt++;	rc = ub_submit_scsi(sc, cmd);	spin_unlock_irqrestore(&sc->lock, flags);	if (rc != 0) {		printk("ub: reading capacity: submit error (%d)\n", rc); /* P3 */		goto err_submit;	}	wait_for_completion(&compl);	if (cmd->error != 0) {		printk("ub: reading capacity: error %d\n", cmd->error); /* P3 */		rc = -EIO;		goto err_read;	}	if (cmd->act_len != 8) {		printk("ub: reading capacity: size %d\n", cmd->act_len); /* P3 */		rc = -EIO;		goto err_read;	}	/* sd.c special-cases sector size of 0 to mean 512. Needed? Safe? */	nsec = be32_to_cpu(*(__be32 *)p) + 1;	bsize = be32_to_cpu(*(__be32 *)(p + 4));	switch (bsize) {	case 512:	shift = 0;	break;	case 1024:	shift = 1;	break;	case 2048:	shift = 2;	break;	case 4096:	shift = 3;	break;	default:		printk("ub: Bad sector size %u\n", bsize); /* P3 */		rc = -EDOM;		goto err_inv_bsize;	}	ret->bsize = bsize;	ret->bshift = shift;	ret->nsec = nsec << shift;	rc = 0;err_inv_bsize:err_read:err_submit:	kfree(cmd);err_alloc:	return rc;}/* */static void ub_probe_urb_complete(struct urb *urb, struct pt_regs *pt){	struct completion *cop = urb->context;	complete(cop);}static void ub_probe_timeout(unsigned long arg){	struct completion *cop = (struct completion *) arg;	complete(cop);}/* * Get number of LUNs by the way of Bulk GetMaxLUN command. */static int ub_sync_getmaxlun(struct ub_dev *sc){	int ifnum = sc->intf->cur_altsetting->desc.bInterfaceNumber;	unsigned char *p;	enum { ALLOC_SIZE = 1 };	struct usb_ctrlrequest *cr;	struct completion compl;	struct timer_list timer;	int nluns;	int rc;	init_completion(&compl);	rc = -ENOMEM;	if ((p = kmalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)		goto err_alloc;	*p = 55;	cr = &sc->work_cr;	cr->bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE;	cr->bRequest = US_BULK_GET_MAX_LUN;	cr->wValue = cpu_to_le16(0);	cr->wIndex = cpu_to_le16(ifnum);	cr->wLength = cpu_to_le16(1);	usb_fill_control_urb(&sc->work_urb, sc->dev, sc->recv_ctrl_pipe,	    (unsigned char*) cr, p, 1, ub_probe_urb_complete, &compl);	sc->work_urb.actual_length = 0;	sc->work_urb.error_count = 0;	sc->work_urb.status = 0;	if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) {		if (rc == -EPIPE) {			printk("%s: Stall submitting GetMaxLUN, using 1 LUN\n",			     sc->name); /* P3 */		} else {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -