📄 ub.c
字号:
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 + -