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

📄 ub.c

📁 Linux块设备驱动源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	bcb->Lun = (cmd->lun != NULL) ? cmd->lun->num : 0;	bcb->Length = cmd->cdb_len;	/* copy the command payload */	memcpy(bcb->CDB, cmd->cdb, UB_MAX_CDB_SIZE);	UB_INIT_COMPLETION(sc->work_done);	sc->last_pipe = sc->send_bulk_pipe;	usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->send_bulk_pipe,	    bcb, US_BULK_CB_WRAP_LEN, ub_urb_complete, sc);	/* Fill what we shouldn't be filling, because usb-storage did so. */	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) {		/* XXX Clear stalls */		ub_complete(&sc->work_done);		return rc;	}	sc->work_timer.expires = jiffies + UB_URB_TIMEOUT;	add_timer(&sc->work_timer);	cmd->state = UB_CMDST_CMD;	ub_cmdtr_state(sc, cmd);	return 0;}/* * Timeout handler. */static void ub_urb_timeout(unsigned long arg){	struct ub_dev *sc = (struct ub_dev *) arg;	unsigned long flags;	spin_lock_irqsave(&sc->lock, flags);	usb_unlink_urb(&sc->work_urb);	spin_unlock_irqrestore(&sc->lock, flags);}/* * Completion routine for the work URB. * * This can be called directly from usb_submit_urb (while we have * the sc->lock taken) and from an interrupt (while we do NOT have * the sc->lock taken). Therefore, bounce this off to a tasklet. */static void ub_urb_complete(struct urb *urb, struct pt_regs *pt){	struct ub_dev *sc = urb->context;	ub_complete(&sc->work_done);	tasklet_schedule(&sc->tasklet);}static void ub_scsi_action(unsigned long _dev){	struct ub_dev *sc = (struct ub_dev *) _dev;	unsigned long flags;	spin_lock_irqsave(&sc->lock, flags);	del_timer(&sc->work_timer);	ub_scsi_dispatch(sc);	spin_unlock_irqrestore(&sc->lock, flags);}static void ub_scsi_dispatch(struct ub_dev *sc){	struct ub_scsi_cmd *cmd;	int rc;	while ((cmd = ub_cmdq_peek(sc)) != NULL) {		if (cmd->state == UB_CMDST_DONE) {			ub_cmdq_pop(sc);			(*cmd->done)(sc, cmd);		} else if (cmd->state == UB_CMDST_INIT) {			ub_cmdtr_new(sc, cmd);			if ((rc = ub_scsi_cmd_start(sc, cmd)) == 0)				break;			cmd->error = rc;			cmd->state = UB_CMDST_DONE;			ub_cmdtr_state(sc, cmd);		} else {			if (!ub_is_completed(&sc->work_done))				break;			ub_scsi_urb_compl(sc, cmd);		}	}}static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd){	struct urb *urb = &sc->work_urb;	struct bulk_cs_wrap *bcs;	int rc;	if (atomic_read(&sc->poison)) {		/* A little too simplistic, I feel... */		goto Bad_End;	}	if (cmd->state == UB_CMDST_CLEAR) {		if (urb->status == -EPIPE) {			/*			 * STALL while clearning STALL.			 * The control pipe clears itself - nothing to do.			 * XXX Might try to reset the device here and retry.			 */			printk(KERN_NOTICE "%s: stall on control pipe\n",			    sc->name);			goto Bad_End;		}		/*		 * We ignore the result for the halt clear.		 */		/* reset the endpoint toggle */		usb_settoggle(sc->dev, usb_pipeendpoint(sc->last_pipe),			usb_pipeout(sc->last_pipe), 0);		ub_state_sense(sc, cmd);	} else if (cmd->state == UB_CMDST_CLR2STS) {		if (urb->status == -EPIPE) {			/*			 * STALL while clearning STALL.			 * The control pipe clears itself - nothing to do.			 * XXX Might try to reset the device here and retry.			 */			printk(KERN_NOTICE "%s: stall on control pipe\n",			    sc->name);			goto Bad_End;		}		/*		 * We ignore the result for the halt clear.		 */		/* reset the endpoint toggle */		usb_settoggle(sc->dev, usb_pipeendpoint(sc->last_pipe),			usb_pipeout(sc->last_pipe), 0);		ub_state_stat(sc, cmd);	} else if (cmd->state == UB_CMDST_CLRRS) {		if (urb->status == -EPIPE) {			/*			 * STALL while clearning STALL.			 * The control pipe clears itself - nothing to do.			 * XXX Might try to reset the device here and retry.			 */			printk(KERN_NOTICE "%s: stall on control pipe\n",			    sc->name);			goto Bad_End;		}		/*		 * We ignore the result for the halt clear.		 */		/* reset the endpoint toggle */		usb_settoggle(sc->dev, usb_pipeendpoint(sc->last_pipe),			usb_pipeout(sc->last_pipe), 0);		ub_state_stat_counted(sc, cmd);	} else if (cmd->state == UB_CMDST_CMD) {		if (urb->status == -EPIPE) {			rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe);			if (rc != 0) {				printk(KERN_NOTICE "%s: "				    "unable to submit clear (%d)\n",				    sc->name, rc);				/*				 * This is typically ENOMEM or some other such shit.				 * Retrying is pointless. Just do Bad End on it...				 */				goto Bad_End;			}			cmd->state = UB_CMDST_CLEAR;			ub_cmdtr_state(sc, cmd);			return;		}		if (urb->status != 0) {			goto Bad_End;		}		if (urb->actual_length != US_BULK_CB_WRAP_LEN) {			/* XXX Must do reset here to unconfuse the device */			goto Bad_End;		}		if (cmd->dir == UB_DIR_NONE || cmd->nsg < 1) {			ub_state_stat(sc, cmd);			return;		}		// udelay(125);		// usb-storage has this		ub_data_start(sc, cmd);	} else if (cmd->state == UB_CMDST_DATA) {		if (urb->status == -EPIPE) {			rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe);			if (rc != 0) {				printk(KERN_NOTICE "%s: "				    "unable to submit clear (%d)\n",				    sc->name, rc);				/*				 * This is typically ENOMEM or some other such shit.				 * Retrying is pointless. Just do Bad End on it...				 */				goto Bad_End;			}			cmd->state = UB_CMDST_CLR2STS;			ub_cmdtr_state(sc, cmd);			return;		}		if (urb->status == -EOVERFLOW) {			/*			 * A babble? Failure, but we must transfer CSW now.			 * XXX This is going to end in perpetual babble. Reset.			 */			cmd->error = -EOVERFLOW;	/* A cheap trick... */			ub_state_stat(sc, cmd);			return;		}		if (urb->status != 0)			goto Bad_End;		cmd->act_len += urb->actual_length;		ub_cmdtr_act_len(sc, cmd);		if (++cmd->current_sg < cmd->nsg) {			ub_data_start(sc, cmd);			return;		}		ub_state_stat(sc, cmd);	} else if (cmd->state == UB_CMDST_STAT) {		if (urb->status == -EPIPE) {			rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe);			if (rc != 0) {				printk(KERN_NOTICE "%s: "				    "unable to submit clear (%d)\n",				    sc->name, rc);				/*				 * This is typically ENOMEM or some other such shit.				 * Retrying is pointless. Just do Bad End on it...				 */				goto Bad_End;			}			/*			 * Having a stall when getting CSW is an error, so			 * make sure uppper levels are not oblivious to it.			 */			cmd->error = -EIO;		/* A cheap trick... */			cmd->state = UB_CMDST_CLRRS;			ub_cmdtr_state(sc, cmd);			return;		}		if (urb->status == -EOVERFLOW) {			/*			 * XXX We are screwed here. Retrying is pointless,			 * because the pipelined data will not get in until			 * we read with a big enough buffer. We must reset XXX.			 */			goto Bad_End;		}		if (urb->status != 0)			goto Bad_End;		if (urb->actual_length == 0) {			ub_state_stat_counted(sc, cmd);			return;		}		/*		 * Check the returned Bulk protocol status.		 * The status block has to be validated first.		 */		bcs = &sc->work_bcs;		if (sc->signature == cpu_to_le32(0)) {			/*			 * This is the first reply, so do not perform the check.			 * Instead, remember the signature the device uses			 * for future checks. But do not allow a nul.			 */			sc->signature = bcs->Signature;			if (sc->signature == cpu_to_le32(0)) {				ub_state_stat_counted(sc, cmd);				return;			}		} else {			if (bcs->Signature != sc->signature) {				ub_state_stat_counted(sc, cmd);				return;			}		}		if (bcs->Tag != cmd->tag) {			/*			 * This usually happens when we disagree with the			 * device's microcode about something. For instance,			 * a few of them throw this after timeouts. They buffer			 * commands and reply at commands we timed out before.			 * Without flushing these replies we loop forever.			 */			ub_state_stat_counted(sc, cmd);			return;		}		rc = le32_to_cpu(bcs->Residue);		if (rc != cmd->len - cmd->act_len) {			/*			 * It is all right to transfer less, the caller has			 * to check. But it's not all right if the device			 * counts disagree with our counts.			 */			/* P3 */ printk("%s: resid %d len %d act %d\n",			    sc->name, rc, cmd->len, cmd->act_len);			goto Bad_End;		}		switch (bcs->Status) {		case US_BULK_STAT_OK:			break;		case US_BULK_STAT_FAIL:			ub_state_sense(sc, cmd);			return;		case US_BULK_STAT_PHASE:			/* XXX We must reset the transport here */			/* P3 */ printk("%s: status PHASE\n", sc->name);			goto Bad_End;		default:			printk(KERN_INFO "%s: unknown CSW status 0x%x\n",			    sc->name, bcs->Status);			goto Bad_End;		}		/* Not zeroing error to preserve a babble indicator */		if (cmd->error != 0) {			ub_state_sense(sc, cmd);			return;		}		cmd->state = UB_CMDST_DONE;		ub_cmdtr_state(sc, cmd);		ub_cmdq_pop(sc);		(*cmd->done)(sc, cmd);	} else if (cmd->state == UB_CMDST_SENSE) {		ub_state_done(sc, cmd, -EIO);	} else {		printk(KERN_WARNING "%s: "		    "wrong command state %d\n",		    sc->name, cmd->state);		goto Bad_End;	}	return;Bad_End: /* Little Excel is dead */	ub_state_done(sc, cmd, -EIO);}/* * Factorization helper for the command state machine: * Initiate a data segment transfer. */static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd){	struct scatterlist *sg = &cmd->sgv[cmd->current_sg];	int pipe;	int rc;	UB_INIT_COMPLETION(sc->work_done);	if (cmd->dir == UB_DIR_READ)		pipe = sc->recv_bulk_pipe;	else		pipe = sc->send_bulk_pipe;	sc->last_pipe = pipe;	usb_fill_bulk_urb(&sc->work_urb, sc->dev, pipe,	    page_address(sg->page) + sg->offset, sg->length,	    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) {		/* XXX Clear stalls */		ub_complete(&sc->work_done);		ub_state_done(sc, cmd, rc);		return;	}	sc->work_timer.expires = jiffies + UB_DATA_TIMEOUT;	add_timer(&sc->work_timer);	cmd->state = UB_CMDST_DATA;	ub_cmdtr_state(sc, cmd);}/* * Factorization helper for the command state machine: * Finish the command. */static void ub_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc){	cmd->error = rc;	cmd->state = UB_CMDST_DONE;	ub_cmdtr_state(sc, cmd);	ub_cmdq_pop(sc);	(*cmd->done)(sc, cmd);}/* * Factorization helper for the command state machine: * Submit a CSW read. */static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd){	int rc;	UB_INIT_COMPLETION(sc->work_done);	sc->last_pipe = sc->recv_bulk_pipe;	usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->recv_bulk_pipe,	    &sc->work_bcs, US_BULK_CS_WRAP_LEN, 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) {		/* XXX Clear stalls */		ub_complete(&sc->work_done);		ub_state_done(sc, cmd, rc);		return -1;	}	sc->work_timer.expires = jiffies + UB_STAT_TIMEOUT;	add_timer(&sc->work_timer);	return 0;}/* * Factorization helper for the command state machine: * Submit a CSW read and go to STAT state. */static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd){	if (__ub_state_stat(sc, cmd) != 0)		return;	cmd->stat_count = 0;	cmd->state = UB_CMDST_STAT;	ub_cmdtr_state(sc, cmd);}/* * Factorization helper for the command state machine: * Submit a CSW read and go to STAT state with counter (along [C] path). */static void ub_state_stat_counted(struct ub_dev *sc, struct ub_scsi_cmd *cmd){	if (++cmd->stat_count >= 4) {		ub_state_sense(sc, cmd);		return;	}	if (__ub_state_stat(sc, cmd) != 0)		return;	cmd->state = UB_CMDST_STAT;	ub_cmdtr_state(sc, cmd);}/* * Factorization helper for the command state machine: * Submit a REQUEST SENSE and go to SENSE state. */static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd){	struct ub_scsi_cmd *scmd;	struct scatterlist *sg;	int rc;	if (cmd->cdb[0] == REQUEST_SENSE) {		rc = -EPIPE;		goto error;	}

⌨️ 快捷键说明

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