All of lore.kernel.org
 help / color / mirror / Atom feed
From: Oliver Neukum <oliver@neukum.org>
To: Pete Zaitcev <zaitcev@redhat.com>
Cc: greg@kroah.com, arjanv@redhat.com, jgarzik@redhat.com,
	tburke@redhat.com, linux-kernel@vger.kernel.org,
	<stern@rowland.harvard.edu>, <mdharm-usb@one-eyed-alien.net>,
	<david-b@pacbell.net>
Subject: Re: drivers/block/ub.c
Date: Sat, 26 Jun 2004 22:35:15 +0200	[thread overview]
Message-ID: <200406262235.15688.oliver@neukum.org> (raw)
In-Reply-To: <20040626130645.55be13ce@lembas.zaitcev.lan>


> +/* command block wrapper */
> +struct bulk_cb_wrap {
> +	u32	Signature;		/* contains 'USBC' */
> +	u32	Tag;			/* unique per command id */
> +	u32	DataTransferLength;	/* size of data */
> +	u8	Flags;			/* direction in bit 0 */
> +	u8	Lun;			/* LUN normally 0 */
> +	u8	Length;			/* of of the CDB */
> +	u8	CDB[MAX_CDB_SIZE];	/* max command */
> +};

should be packed attributed

> +#define US_BULK_CB_WRAP_LEN	31
> +#define US_BULK_CB_SIGN		0x43425355	/*spells out USBC */
> +#define US_BULK_FLAG_IN		1
> +#define US_BULK_FLAG_OUT	0
> +
> +/* command status wrapper */
> +struct bulk_cs_wrap {
> +	u32	Signature;		/* should = 'USBS' */
> +	u32	Tag;			/* same as original command */
> +	u32	Residue;		/* amount not transferred */
> +	u8	Status;			/* see below */
> +};

should be packed attributed

> +#define US_BULK_CS_WRAP_LEN	13
> +#define US_BULK_CS_SIGN		0x53425355	/* spells out 'USBS' */
> +/* This is for Olympus Camedia digital cameras */
> +#define US_BULK_CS_OLYMPUS_SIGN	0x55425355	/* spells out 'USBU' */
> +#define US_BULK_STAT_OK		0
> +#define US_BULK_STAT_FAIL	1
> +#define US_BULK_STAT_PHASE	2
> +
> +/* bulk-only class specific requests */
> +#define US_BULK_RESET_REQUEST	0xff
> +#define US_BULK_GET_MAX_LUN	0xfe
> +
> +/*
> + */
> +struct ub_dev;
> +
> +#define UB_MAX_REQ_SG	1
> +
> +/*
> + * An instance of a SCSI command in transit.
> + */
> +#define UB_DIR_NONE	0
> +#define UB_DIR_READ	1
> +#define UB_DIR_ILLEGAL2	2
> +#define UB_DIR_WRITE	3
> +
> +enum ub_scsi_cmd_state {
> +	UB_CMDST_INIT,			/* Initial state */
> +	UB_CMDST_CMD,			/* Command submitted */
> +	UB_CMDST_DATA,			/* Data phase */
> +	UB_CMDST_CLR2STS,		/* Clearing before requesting status */
> +	UB_CMDST_STAT,			/* Status phase */
> +	UB_CMDST_CLEAR,			/* Clearing a stall (halt, actually) */
> +	UB_CMDST_SENSE,			/* Sending Request Sense */
> +	UB_CMDST_DONE			/* Final state */
> +};
> +
> +struct ub_scsi_cmd {
> +	unsigned char cdb[MAX_CDB_SIZE];
> +	unsigned char cdb_len;
> +
> +	unsigned char dir;		/* 0 - none, 1 - read, 3 - write. */
> +	enum ub_scsi_cmd_state state;
> +	unsigned int tag;
> +
> +	int error;			/* Return code - valid upon done */
> +	int act_len;			/* Return size */
> +
> +	int stat_count;			/* Retries getting status. */
> +
> +	/*
> +	 * We do not support transfers from highmem pages
> +	 * because the underlying USB framework does not.
> +	 *
> +	 * XXX Actually, there is a (very fresh and buggy) support
> +	 * for transfers under control of struct scatterlist, usb_map_sg()
> +	 * in 2.6.6, but it seems to have issues with highmem.
> +	 */
> +	char *data;			/* Requested buffer */
> +	unsigned int len;		/* Requested length */
> +	// struct scatterlist sgv[UB_MAX_REQ_SG];
> +
> +	void (*done)(struct ub_dev *, struct ub_scsi_cmd *);
> +	void *back;
> +};
> +
> +/*
> + */
> +struct ub_capacity {
> +	unsigned long nsec;		/* Linux size - 512 byte sectors */
> +	unsigned int bsize;		/* Linux hardsect_size */
> +	unsigned int bshift;		/* Shift between 512 and hard sects */
> +};
> +
> +/*
> + * The SCSI command tracing structure.
> + */
> +
> +#define SCMD_ST_HIST_SZ   8
> +#define SCMD_TRACE_SZ     5
> +
> +struct ub_scsi_cmd_trace {
> +	unsigned int tag;
> +	unsigned char op;
> +	unsigned char dir;
> +	unsigned int req_size, act_size;
> +	int hcur;
> +	enum ub_scsi_cmd_state st_hst[SCMD_ST_HIST_SZ];		/* u8? */
> +};
> +
> +struct ub_scsi_trace {
> +	int cur;
> +	struct ub_scsi_cmd_trace vec[SCMD_TRACE_SZ];
> +};
> +
> +/*
> + * The UB device instance.
> + */
> +struct ub_dev {
> +	spinlock_t lock;
> +	unsigned int id;		/* Number among ub's */
> +
> +	unsigned int tagcnt;
> +	int poison;
> +	char name[8];
> +	struct usb_device *dev;
> +	struct usb_interface *intf;
> +
> +	struct ub_capacity capacity; 
> +	struct gendisk *disk;
> +
> +	unsigned int send_bulk_pipe;  /* cached pipe values */
> +	unsigned int recv_bulk_pipe;
> +	unsigned int send_ctrl_pipe;
> +	unsigned int recv_ctrl_pipe;
> +
> +	struct tasklet_struct urb_tasklet;
> +
> +	/* XXX Use Ingo's mempool (once we have more than one) */
> +	int cmda[1];
> +	struct ub_scsi_cmd cmdv[1];
> +
> +	int busy;
> +	struct ub_scsi_cmd *top_cmd;	/* XXX Under ->busy until we have a queue */
> +	struct ub_scsi_cmd top_rqs_cmd;	/* REQUEST SENSE */
> +	unsigned char top_sense[SENSE_SIZE];
> +
> +	struct urb work_urb;
> +	int last_pipe;			/* What might need clearing */
> +	struct bulk_cb_wrap work_bcb;
> +	struct bulk_cs_wrap work_bcs;
> +	struct usb_ctrlrequest work_cr;
> +
> +	struct ub_scsi_trace tr;
> +};
> +
> +/*
> + */
> +static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
> +static void ub_end_rq(struct request *rq, int uptodate);
> +static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
> +static void ub_scsi_urb_complete(struct urb *urb, struct pt_regs *pt);
> +static void ub_scsi_urb_action(unsigned long _dev);
> +static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
> +static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
> +static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
> +    int stalled_pipe);
> +static int ub_submit_top_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
> +
> +/*
> + */
> +static struct usb_device_id ub_usb_ids[] = {
> +	{ USB_DEVICE_VER(0x0781, 0x0002, 0x0009, 0x0009) },	/* SDDR-31 */
> +	{ }
> +};
> +
> +MODULE_DEVICE_TABLE(usb, ub_usb_ids);
> +
> +static unsigned int ub_host_id;
> +
> +/*
> + * The SCSI command tracing procedures.
> + */
> +
> +static void ub_cmdtr_new(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
> +{
> +	int n;
> +	struct ub_scsi_cmd_trace *t;
> +
> +	if ((n = sc->tr.cur + 1) == SCMD_TRACE_SZ) n = 0;
> +	t = &sc->tr.vec[n];
> +
> +	memset(t, 0, sizeof(struct ub_scsi_cmd_trace));
> +	t->tag = cmd->tag;
> +	t->op = cmd->cdb[0];
> +	t->dir = cmd->dir;
> +	t->req_size = cmd->len;
> +	t->st_hst[0] = cmd->state;
> +
> +	sc->tr.cur = n;
> +}
> +
> +static void ub_cmdtr_state(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
> +{
> +	int n;
> +	struct ub_scsi_cmd_trace *t;
> +
> +	t = &sc->tr.vec[sc->tr.cur];
> +	if ((n = t->hcur + 1) == SCMD_ST_HIST_SZ) n = 0;
> +	t->st_hst[n] = cmd->state;
> +	t->hcur = n;
> +}
> +
> +static void ub_cmdtr_act_len(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
> +{
> +	struct ub_scsi_cmd_trace *t;
> +
> +	t = &sc->tr.vec[sc->tr.cur];
> +	t->act_size = cmd->act_len;
> +}
> +
> +/* The struct disk_attribute must match drivers/block/genhd.c */
> +struct disk_attribute {
> +	struct attribute attr;
> +	ssize_t (*show)(struct gendisk *, char *);
> +};
> +
> +static ssize_t ub_sysdiag_show(struct gendisk *disk, char *page)
> +{
> +	struct ub_dev *sc = disk->private_data;
> +	int cnt = 0;
> +	unsigned long flags;
> +	int nc, nh;
> +	int i, j;
> +	struct ub_scsi_cmd_trace *t;
> +
> +	spin_lock_irqsave(&sc->lock, flags);
> +	if ((nc = sc->tr.cur + 1) == SCMD_TRACE_SZ) nc = 0;
> +	for (j = 0; j < SCMD_TRACE_SZ; j++) {
> +		t = &sc->tr.vec[nc];
> +
> +		cnt += sprintf(page + cnt, "%08x %02x", t->tag, t->op);
> +		cnt += sprintf(page + cnt, " %d", t->dir);
> +		cnt += sprintf(page + cnt, " [%5d %5d]", t->req_size, t->act_size);
> +		if ((nh = t->hcur + 1) == SCMD_ST_HIST_SZ) nh = 0;
> +		for (i = 0; i < SCMD_ST_HIST_SZ; i++) {
> +			cnt += sprintf(page + cnt, " %d", t->st_hst[nh]);
> +			if (++nh == SCMD_ST_HIST_SZ) nh = 0;
> +		}
> +		cnt += sprintf(page + cnt, "\n");
> +
> +		if (++nc == SCMD_TRACE_SZ) nc = 0;
> +	}
> +	spin_unlock_irqrestore(&sc->lock, flags);
> +	return cnt;
> +}
> +
> +static struct disk_attribute ub_sysdiag_attr = {
> +        .attr = {.name = "diag", .mode = S_IRUGO },
> +	.show = ub_sysdiag_show
> +};
> +
> +static int ub_sysdiag_create(struct ub_dev *sc)
> +{
> +	return sysfs_create_file(&sc->disk->kobj, &ub_sysdiag_attr.attr);
> +}
> +
> +/*
> + * The "command allocator".
> + */
> +static struct ub_scsi_cmd *ub_get_cmd(struct ub_dev *sc)
> +{
> +	struct ub_scsi_cmd *ret;
> +
> +	if (sc->cmda[0])
> +		return NULL;
> +	ret = &sc->cmdv[0];
> +	sc->cmda[0] = 1;
> +	return ret;
> +}
> +
> +static void ub_put_cmd(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
> +{
> +	if (cmd != &sc->cmdv[0]) {
> +		printk(KERN_WARNING DRV_NAME ": "
> +		    "releasing a foreign cmd %p\n", cmd);
> +		return;
> +	}
> +	if (!sc->cmda[0]) {
> +		printk(KERN_WARNING DRV_NAME ": "
> +		    "releasing a free cmd\n");
> +		return;
> +	}
> +	sc->cmda[0] = 0;
> +}
> +
> +/*
> + * The request function is our main entry point
> + */
> +
> +static inline int ub_bd_rq_fn_1(request_queue_t *q)
> +{
> +#if 0
> +	int writing = 0, pci_dir, i, n_elem;
> +	u32 tmp;
> +	unsigned int msg_size;
> +#endif
> +	struct ub_dev *sc = q->queuedata;
> +	struct request *rq;
> +#if 0 /* We use rq->buffer for now */
> +	struct scatterlist *sg;
> +	int n_elem;
> +#endif
> +	struct ub_scsi_cmd *cmd;
> +	int ub_dir;
> +	unsigned int block, nblks;
> +	int rc;
> +
> +	if ((rq = elv_next_request(q)) == NULL)
> +		return 1;
> +
> +	if ((cmd = ub_get_cmd(sc)) == NULL) {
> +		blk_stop_queue(q);
> +		return 1;
> +	}
> +
> +	blkdev_dequeue_request(rq);
> +
> +	if (rq_data_dir(rq) == WRITE)
> +		ub_dir = UB_DIR_WRITE;
> +	else
> +		ub_dir = UB_DIR_READ;
> +
> +	/*
> +	 * get scatterlist from block layer
> +	 */
> +#if 0 /* We use rq->buffer for now */
> +	sg = &cmd->sgv[0];
> +	n_elem = blk_rq_map_sg(q, rq, sg);
> +	if (n_elem <= 0) {
> +		ub_put_cmd(sc, cmd);
> +		ub_end_rq(rq, 0);
> +		blk_start_queue(q);
> +		return 0;		/* request with no s/g entries? */
> +	}
> +
> +	if (n_elem != 1) {		/* Paranoia */
> +		printk(KERN_WARNING DRV_NAME ": request with %d segments\n",
> +		    n_elem);
> +		ub_put_cmd(sc, cmd);
> +		ub_end_rq(rq, 0);
> +		blk_start_queue(q);
> +		return 0;
> +	}
> +#endif
> +	/*
> +	 * XXX Unfortunately, this check does not work. It is quite possible
> +	 * to get bogus non-null rq->buffer if you allow sg by mistake.
> +	 */
> +	if (rq->buffer == NULL) {
> +		/*
> +		 * This must not happen if we set the queue right.
> +		 * The block level must create bounce buffers for us.
> +		 */
> +		static int do_print = 1;
> +		if (do_print) {
> +			printk(KERN_WARNING DRV_NAME ": unmapped request\n");
> +			do_print = 0;
> +		}
> +		ub_put_cmd(sc, cmd);
> +		ub_end_rq(rq, 0);
> +		blk_start_queue(q);
> +		return 0;
> +	}
> +
> +#if 0 /* Just to show what carmel does in this place... We won't need this. */
> +	/* map scatterlist to PCI bus addresses */
> +	n_elem = pci_map_sg(host->pdev, sg, n_elem, pci_dir);
> +	if (n_elem <= 0) {
> +		carm_end_rq(host, crq, 0);
> +		return 1;		/* request with no s/g entries? */
> +	}
> +	crq->n_elem = n_elem;
> +	crq->port = port;
> +	host->hw_sg_used += n_elem;
> +#endif
> +
> +	/*
> +	 * build the command
> +	 */
> +	block = rq->sector;
> +	nblks = rq->nr_sectors;
> +
> +	memset(cmd, 0, sizeof(struct ub_scsi_cmd));
> +	cmd->cdb[0] = (ub_dir == UB_DIR_READ)? READ_10: WRITE_10;
> +	/* 10-byte uses 4 bytes of LBA: 2147483648KB, 2097152MB, 2048GB */
> +	cmd->cdb[2] = block >> 24;
> +	cmd->cdb[3] = block >> 16;
> +	cmd->cdb[4] = block >> 8;
> +	cmd->cdb[5] = block;

we have macros for that.

> +	cmd->cdb[7] = nblks >> 8;
> +	cmd->cdb[8] = nblks;

dito

	Regards
		Oliver

  parent reply	other threads:[~2004-06-26 20:34 UTC|newest]

Thread overview: 71+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-06-26 20:06 drivers/block/ub.c Pete Zaitcev
2004-06-26 20:12 ` drivers/block/ub.c Matthew Dharm
2004-06-27  2:08   ` drivers/block/ub.c Pete Zaitcev
2004-06-27  3:30     ` drivers/block/ub.c Matthew Dharm
2004-07-12  0:10     ` [usb-storage] drivers/block/ub.c Pat LaVarre
2004-06-26 20:35 ` Oliver Neukum [this message]
2004-06-26 21:41   ` drivers/block/ub.c David S. Miller
2004-06-26 21:56     ` drivers/block/ub.c Oliver Neukum
2004-06-26 22:07       ` drivers/block/ub.c David S. Miller
2004-06-26 22:36         ` drivers/block/ub.c Oliver Neukum
2004-06-26 23:20           ` drivers/block/ub.c David S. Miller
2004-06-27  4:31             ` drivers/block/ub.c Oliver Neukum
2004-06-27  6:34               ` drivers/block/ub.c David S. Miller
2004-06-27 10:42                 ` drivers/block/ub.c Oliver Neukum
2004-06-27 21:26                   ` drivers/block/ub.c David S. Miller
2004-06-28 14:15                     ` drivers/block/ub.c Scott Wood
2004-06-28 20:25                       ` drivers/block/ub.c David S. Miller
2004-06-28 20:48                         ` drivers/block/ub.c Scott Wood
2004-06-28 20:58                           ` drivers/block/ub.c David S. Miller
2004-06-28 20:50                         ` drivers/block/ub.c Matthew Dharm
2004-06-28 20:59                           ` drivers/block/ub.c David S. Miller
2004-06-28 21:01                           ` drivers/block/ub.c Pete Zaitcev
2004-06-28 23:52                             ` drivers/block/ub.c Matthew Dharm
2004-06-28 20:57                         ` drivers/block/ub.c Oliver Neukum
2004-06-28 21:03                           ` drivers/block/ub.c David S. Miller
2004-06-28 21:18                             ` drivers/block/ub.c Scott Wood
2004-06-28 22:22                               ` drivers/block/ub.c David S. Miller
2004-06-28 22:31                                 ` drivers/block/ub.c Scott Wood
2004-06-28 22:40                                 ` drivers/block/ub.c Roland Dreier
2004-06-29  1:54                             ` drivers/block/ub.c Robert White
2004-06-29  2:15                               ` drivers/block/ub.c David S. Miller
2004-06-29  2:49                                 ` drivers/block/ub.c Robert White
2004-06-29 18:31                             ` drivers/block/ub.c Andy Isaacson
2004-07-05 10:01                             ` drivers/block/ub.c Roman Zippel
2004-06-29  7:12                         ` drivers/block/ub.c Vojtech Pavlik
2004-06-29  1:39                     ` drivers/block/ub.c Robert White
2004-06-29 17:02                     ` drivers/block/ub.c Kurt Garloff
2004-06-26 22:54   ` drivers/block/ub.c Andries Brouwer
2004-06-26 22:59     ` drivers/block/ub.c Oliver Neukum
2004-06-26 23:08       ` drivers/block/ub.c Andries Brouwer
2004-06-27  5:04         ` drivers/block/ub.c Oliver Neukum
2004-06-27 14:08           ` drivers/block/ub.c Andries Brouwer
2004-06-27 14:24             ` drivers/block/ub.c Oliver Neukum
2004-06-27 15:19               ` drivers/block/ub.c Alan Stern
2004-06-27 15:45                 ` drivers/block/ub.c Andries Brouwer
2004-06-28 23:58                   ` drivers/block/ub.c Jeff Garzik
2004-06-28  0:10                 ` drivers/block/ub.c Pete Zaitcev
2004-06-28 16:01                   ` drivers/block/ub.c Alan Stern
2004-06-27 15:23               ` drivers/block/ub.c Andries Brouwer
2004-06-27 16:11                 ` drivers/block/ub.c Oliver Neukum
2004-06-26 22:46 ` drivers/block/ub.c Oliver Neukum
2004-06-27  3:52   ` drivers/block/ub.c Alan Stern
2004-06-27  4:05 ` drivers/block/ub.c Alan Stern
2004-06-27  5:02   ` drivers/block/ub.c Greg KH
2004-06-27 15:23     ` drivers/block/ub.c Alan Stern
2004-06-27 20:29       ` drivers/block/ub.c Pete Zaitcev
2004-06-27 21:03         ` drivers/block/ub.c Matthew Dharm
2004-06-28 15:40         ` drivers/block/ub.c Alan Stern
2004-06-28 16:42           ` drivers/block/ub.c Oliver Neukum
2004-06-28 19:50             ` drivers/block/ub.c Alan Stern
2004-06-27  5:35   ` drivers/block/ub.c Matthew Dharm
2004-06-27 15:28     ` drivers/block/ub.c Alan Stern
2004-06-27 22:56 ` drivers/block/ub.c David Brownell
2004-06-27 23:43   ` drivers/block/ub.c Pete Zaitcev
2004-06-28 15:05     ` drivers/block/ub.c David Brownell
2004-06-28 15:56     ` drivers/block/ub.c Alan Stern
2004-06-28 16:23       ` drivers/block/ub.c David Brownell
2004-06-28 16:46         ` drivers/block/ub.c Oliver Neukum
2004-06-28 17:13           ` drivers/block/ub.c David Brownell
     [not found] ` <mailman.1088290201.14081.linux-kernel2news@redhat.com>
2004-06-27 23:57   ` drivers/block/ub.c Pete Zaitcev
2004-06-29 11:05 ` drivers/block/ub.c Jeff Garzik

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=200406262235.15688.oliver@neukum.org \
    --to=oliver@neukum.org \
    --cc=arjanv@redhat.com \
    --cc=david-b@pacbell.net \
    --cc=greg@kroah.com \
    --cc=jgarzik@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mdharm-usb@one-eyed-alien.net \
    --cc=stern@rowland.harvard.edu \
    --cc=tburke@redhat.com \
    --cc=zaitcev@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.