2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* The low performance USB storage driver (ub).
|
|
|
|
*
|
|
|
|
* Copyright (c) 1999, 2000 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
|
|
|
|
* Copyright (C) 2004 Pete Zaitcev (zaitcev@yahoo.com)
|
|
|
|
*
|
|
|
|
* This work is a part of Linux kernel, is derived from it,
|
|
|
|
* and is not licensed separately. See file COPYING for details.
|
|
|
|
*
|
|
|
|
* TODO (sorted by decreasing priority)
|
|
|
|
* -- set readonly flag for CDs, set removable flag for CF readers
|
|
|
|
* -- do inquiry and verify we got a disk and not a tape (for LUN mismatch)
|
|
|
|
* -- special case some senses, e.g. 3a/0 -> no media present, reduce retries
|
|
|
|
* -- verify the 13 conditions and do bulk resets
|
|
|
|
* -- kill last_pipe and simply do two-state clearing on both pipes
|
2005-07-31 13:38:30 +08:00
|
|
|
* -- highmem
|
2005-04-17 06:20:36 +08:00
|
|
|
* -- move top_sense and work_bcs into separate allocations (if they survive)
|
|
|
|
* for cache purists and esoteric architectures.
|
2005-07-31 13:38:30 +08:00
|
|
|
* -- Allocate structure for LUN 0 before the first ub_sync_tur, avoid NULL. ?
|
2005-04-17 06:20:36 +08:00
|
|
|
* -- prune comments, they are too volumnous
|
|
|
|
* -- Exterminate P3 printks
|
|
|
|
* -- Resove XXX's
|
|
|
|
* -- Redo "benh's retries", perhaps have spin-up code to handle them. V:D=?
|
2005-07-28 02:43:51 +08:00
|
|
|
* -- CLEAR, CLR2STS, CLRRS seem to be ripe for refactoring.
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/usb.h>
|
2005-10-23 11:15:09 +08:00
|
|
|
#include <linux/usb_usual.h>
|
2005-04-17 06:20:36 +08:00
|
|
|
#include <linux/blkdev.h>
|
|
|
|
#include <linux/devfs_fs_kernel.h>
|
|
|
|
#include <linux/timer.h>
|
|
|
|
#include <scsi/scsi.h>
|
|
|
|
|
|
|
|
#define DRV_NAME "ub"
|
|
|
|
#define DEVFS_NAME DRV_NAME
|
|
|
|
|
|
|
|
#define UB_MAJOR 180
|
|
|
|
|
2005-07-28 02:43:51 +08:00
|
|
|
/*
|
|
|
|
* The command state machine is the key model for understanding of this driver.
|
|
|
|
*
|
|
|
|
* The general rule is that all transitions are done towards the bottom
|
|
|
|
* of the diagram, thus preventing any loops.
|
|
|
|
*
|
|
|
|
* An exception to that is how the STAT state is handled. A counter allows it
|
|
|
|
* to be re-entered along the path marked with [C].
|
|
|
|
*
|
|
|
|
* +--------+
|
|
|
|
* ! INIT !
|
|
|
|
* +--------+
|
|
|
|
* !
|
|
|
|
* ub_scsi_cmd_start fails ->--------------------------------------\
|
|
|
|
* ! !
|
|
|
|
* V !
|
|
|
|
* +--------+ !
|
|
|
|
* ! CMD ! !
|
|
|
|
* +--------+ !
|
|
|
|
* ! +--------+ !
|
|
|
|
* was -EPIPE -->-------------------------------->! CLEAR ! !
|
|
|
|
* ! +--------+ !
|
|
|
|
* ! ! !
|
|
|
|
* was error -->------------------------------------- ! --------->\
|
|
|
|
* ! ! !
|
|
|
|
* /--<-- cmd->dir == NONE ? ! !
|
|
|
|
* ! ! ! !
|
|
|
|
* ! V ! !
|
|
|
|
* ! +--------+ ! !
|
|
|
|
* ! ! DATA ! ! !
|
|
|
|
* ! +--------+ ! !
|
|
|
|
* ! ! +---------+ ! !
|
|
|
|
* ! was -EPIPE -->--------------->! CLR2STS ! ! !
|
|
|
|
* ! ! +---------+ ! !
|
|
|
|
* ! ! ! ! !
|
|
|
|
* ! ! was error -->---- ! --------->\
|
|
|
|
* ! was error -->--------------------- ! ------------- ! --------->\
|
|
|
|
* ! ! ! ! !
|
|
|
|
* ! V ! ! !
|
|
|
|
* \--->+--------+ ! ! !
|
|
|
|
* ! STAT !<--------------------------/ ! !
|
|
|
|
* /--->+--------+ ! !
|
|
|
|
* ! ! ! !
|
|
|
|
* [C] was -EPIPE -->-----------\ ! !
|
|
|
|
* ! ! ! ! !
|
|
|
|
* +<---- len == 0 ! ! !
|
|
|
|
* ! ! ! ! !
|
|
|
|
* ! was error -->--------------------------------------!---------->\
|
|
|
|
* ! ! ! ! !
|
|
|
|
* +<---- bad CSW ! ! !
|
|
|
|
* +<---- bad tag ! ! !
|
|
|
|
* ! ! V ! !
|
|
|
|
* ! ! +--------+ ! !
|
|
|
|
* ! ! ! CLRRS ! ! !
|
|
|
|
* ! ! +--------+ ! !
|
|
|
|
* ! ! ! ! !
|
|
|
|
* \------- ! --------------------[C]--------\ ! !
|
|
|
|
* ! ! ! !
|
|
|
|
* cmd->error---\ +--------+ ! !
|
|
|
|
* ! +--------------->! SENSE !<----------/ !
|
|
|
|
* STAT_FAIL----/ +--------+ !
|
|
|
|
* ! ! V
|
|
|
|
* ! V +--------+
|
|
|
|
* \--------------------------------\--------------------->! DONE !
|
|
|
|
* +--------+
|
|
|
|
*/
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
2005-05-02 07:05:40 +08:00
|
|
|
* This many LUNs per USB device.
|
|
|
|
* Every one of them takes a host, see UB_MAX_HOSTS.
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
2005-06-07 04:54:59 +08:00
|
|
|
#define UB_MAX_LUNS 9
|
2005-05-02 07:05:40 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
*/
|
|
|
|
|
2005-12-17 18:34:12 +08:00
|
|
|
#define UB_PARTS_PER_LUN 8
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
#define UB_MAX_CDB_SIZE 16 /* Corresponds to Bulk */
|
|
|
|
|
|
|
|
#define UB_SENSE_SIZE 18
|
|
|
|
|
|
|
|
/*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* command block wrapper */
|
|
|
|
struct bulk_cb_wrap {
|
|
|
|
__le32 Signature; /* contains 'USBC' */
|
|
|
|
u32 Tag; /* unique per command id */
|
|
|
|
__le32 DataTransferLength; /* size of data */
|
|
|
|
u8 Flags; /* direction in bit 0 */
|
2005-05-02 07:05:40 +08:00
|
|
|
u8 Lun; /* LUN */
|
2005-04-17 06:20:36 +08:00
|
|
|
u8 Length; /* of of the CDB */
|
|
|
|
u8 CDB[UB_MAX_CDB_SIZE]; /* max command */
|
|
|
|
};
|
|
|
|
|
|
|
|
#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 {
|
|
|
|
__le32 Signature; /* should = 'USBS' */
|
|
|
|
u32 Tag; /* same as original command */
|
|
|
|
__le32 Residue; /* amount not transferred */
|
|
|
|
u8 Status; /* see below */
|
|
|
|
};
|
|
|
|
|
|
|
|
#define US_BULK_CS_WRAP_LEN 13
|
|
|
|
#define US_BULK_CS_SIGN 0x53425355 /* spells out 'USBS' */
|
|
|
|
#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;
|
|
|
|
|
2005-09-22 15:48:29 +08:00
|
|
|
#define UB_MAX_REQ_SG 9 /* cdrecord requires 32KB and maybe a header */
|
2005-04-17 06:20:36 +08:00
|
|
|
#define UB_MAX_SECTORS 64
|
|
|
|
|
|
|
|
/*
|
|
|
|
* A second is more than enough for a 32K transfer (UB_MAX_SECTORS)
|
|
|
|
* even if a webcam hogs the bus, but some devices need time to spin up.
|
|
|
|
*/
|
|
|
|
#define UB_URB_TIMEOUT (HZ*2)
|
|
|
|
#define UB_DATA_TIMEOUT (HZ*5) /* ZIP does spin-ups in the data phase */
|
|
|
|
#define UB_STAT_TIMEOUT (HZ*5) /* Same spinups and eject for a dataless cmd. */
|
|
|
|
#define UB_CTRL_TIMEOUT (HZ/2) /* 500ms ought to be enough to clear a stall */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
|
2006-03-03 08:42:59 +08:00
|
|
|
/* P3 */
|
2005-04-17 06:20:36 +08:00
|
|
|
#define UB_DIR_CHAR(c) (((c)==UB_DIR_WRITE)? 'w': \
|
|
|
|
(((c)==UB_DIR_READ)? 'r': 'n'))
|
|
|
|
|
|
|
|
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) */
|
2005-07-28 02:43:51 +08:00
|
|
|
UB_CMDST_CLRRS, /* Clearing before retrying status */
|
2005-04-17 06:20:36 +08:00
|
|
|
UB_CMDST_SENSE, /* Sending Request Sense */
|
|
|
|
UB_CMDST_DONE /* Final state */
|
|
|
|
};
|
|
|
|
|
|
|
|
struct ub_scsi_cmd {
|
|
|
|
unsigned char cdb[UB_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;
|
|
|
|
struct ub_scsi_cmd *next;
|
|
|
|
|
|
|
|
int error; /* Return code - valid upon done */
|
|
|
|
unsigned int act_len; /* Return size */
|
|
|
|
unsigned char key, asc, ascq; /* May be valid if error==-EIO */
|
|
|
|
|
|
|
|
int stat_count; /* Retries getting status. */
|
|
|
|
|
|
|
|
unsigned int len; /* Requested length */
|
2005-08-15 12:16:03 +08:00
|
|
|
unsigned int current_sg;
|
|
|
|
unsigned int nsg; /* sgv[nsg] */
|
|
|
|
struct scatterlist sgv[UB_MAX_REQ_SG];
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-05-02 07:05:40 +08:00
|
|
|
struct ub_lun *lun;
|
2005-04-17 06:20:36 +08:00
|
|
|
void (*done)(struct ub_dev *, struct ub_scsi_cmd *);
|
|
|
|
void *back;
|
|
|
|
};
|
|
|
|
|
2005-12-17 18:16:43 +08:00
|
|
|
struct ub_request {
|
|
|
|
struct request *rq;
|
|
|
|
unsigned int current_try;
|
|
|
|
unsigned int nsg; /* sgv[nsg] */
|
|
|
|
struct scatterlist sgv[UB_MAX_REQ_SG];
|
|
|
|
};
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
*/
|
|
|
|
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 */
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is a direct take-off from linux/include/completion.h
|
|
|
|
* The difference is that I do not wait on this thing, just poll.
|
|
|
|
* When I want to wait (ub_probe), I just use the stock completion.
|
|
|
|
*
|
|
|
|
* Note that INIT_COMPLETION takes no lock. It is correct. But why
|
|
|
|
* in the bloody hell that thing takes struct instead of pointer to struct
|
|
|
|
* is quite beyond me. I just copied it from the stock completion.
|
|
|
|
*/
|
|
|
|
struct ub_completion {
|
|
|
|
unsigned int done;
|
|
|
|
spinlock_t lock;
|
|
|
|
};
|
|
|
|
|
|
|
|
static inline void ub_init_completion(struct ub_completion *x)
|
|
|
|
{
|
|
|
|
x->done = 0;
|
|
|
|
spin_lock_init(&x->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define UB_INIT_COMPLETION(x) ((x).done = 0)
|
|
|
|
|
|
|
|
static void ub_complete(struct ub_completion *x)
|
|
|
|
{
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
spin_lock_irqsave(&x->lock, flags);
|
|
|
|
x->done++;
|
|
|
|
spin_unlock_irqrestore(&x->lock, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ub_is_completed(struct ub_completion *x)
|
|
|
|
{
|
|
|
|
unsigned long flags;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
spin_lock_irqsave(&x->lock, flags);
|
|
|
|
ret = x->done;
|
|
|
|
spin_unlock_irqrestore(&x->lock, flags);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
*/
|
|
|
|
struct ub_scsi_cmd_queue {
|
|
|
|
int qlen, qmax;
|
|
|
|
struct ub_scsi_cmd *head, *tail;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
2005-05-02 07:05:40 +08:00
|
|
|
* The block device instance (one per LUN).
|
|
|
|
*/
|
|
|
|
struct ub_lun {
|
|
|
|
struct ub_dev *udev;
|
|
|
|
struct list_head link;
|
|
|
|
struct gendisk *disk;
|
|
|
|
int id; /* Host index */
|
|
|
|
int num; /* LUN number */
|
|
|
|
char name[16];
|
|
|
|
|
|
|
|
int changed; /* Media was changed */
|
|
|
|
int removable;
|
|
|
|
int readonly;
|
|
|
|
|
2005-12-17 18:16:43 +08:00
|
|
|
struct ub_request urq;
|
|
|
|
|
2005-05-02 07:05:40 +08:00
|
|
|
/* Use Ingo's mempool if or when we have more than one command. */
|
|
|
|
/*
|
|
|
|
* Currently we never need more than one command for the whole device.
|
|
|
|
* However, giving every LUN a command is a cheap and automatic way
|
|
|
|
* to enforce fairness between them.
|
|
|
|
*/
|
|
|
|
int cmda[1];
|
|
|
|
struct ub_scsi_cmd cmdv[1];
|
|
|
|
|
|
|
|
struct ub_capacity capacity;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The USB device instance.
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
|
|
|
struct ub_dev {
|
2005-12-29 06:22:17 +08:00
|
|
|
spinlock_t *lock;
|
2005-04-17 06:20:36 +08:00
|
|
|
atomic_t poison; /* The USB device is disconnected */
|
|
|
|
int openc; /* protected by ub_lock! */
|
|
|
|
/* kref is too implicit for our taste */
|
2005-12-17 18:16:43 +08:00
|
|
|
int reset; /* Reset is running */
|
2005-04-17 06:20:36 +08:00
|
|
|
unsigned int tagcnt;
|
2005-05-02 07:05:40 +08:00
|
|
|
char name[12];
|
2005-04-17 06:20:36 +08:00
|
|
|
struct usb_device *dev;
|
|
|
|
struct usb_interface *intf;
|
|
|
|
|
2005-05-02 07:05:40 +08:00
|
|
|
struct list_head luns;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
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 tasklet;
|
|
|
|
|
|
|
|
struct ub_scsi_cmd_queue cmd_queue;
|
|
|
|
struct ub_scsi_cmd top_rqs_cmd; /* REQUEST SENSE */
|
|
|
|
unsigned char top_sense[UB_SENSE_SIZE];
|
|
|
|
|
|
|
|
struct ub_completion work_done;
|
|
|
|
struct urb work_urb;
|
|
|
|
struct timer_list work_timer;
|
|
|
|
int last_pipe; /* What might need clearing */
|
2005-07-28 02:43:51 +08:00
|
|
|
__le32 signature; /* Learned signature */
|
2005-04-17 06:20:36 +08:00
|
|
|
struct bulk_cb_wrap work_bcb;
|
|
|
|
struct bulk_cs_wrap work_bcs;
|
|
|
|
struct usb_ctrlrequest work_cr;
|
|
|
|
|
2005-12-17 18:16:43 +08:00
|
|
|
struct work_struct reset_work;
|
|
|
|
wait_queue_head_t reset_wait;
|
|
|
|
|
2005-09-22 15:48:29 +08:00
|
|
|
int sg_stat[6];
|
2005-04-17 06:20:36 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
*/
|
|
|
|
static void ub_cleanup(struct ub_dev *sc);
|
2005-07-31 13:51:52 +08:00
|
|
|
static int ub_request_fn_1(struct ub_lun *lun, struct request *rq);
|
2005-12-17 18:16:43 +08:00
|
|
|
static void ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
|
|
|
|
struct ub_scsi_cmd *cmd, struct ub_request *urq);
|
|
|
|
static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
|
|
|
|
struct ub_scsi_cmd *cmd, struct ub_request *urq);
|
2005-04-17 06:20:36 +08:00
|
|
|
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);
|
2005-12-17 18:16:43 +08:00
|
|
|
static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun,
|
|
|
|
struct ub_request *urq, struct ub_scsi_cmd *cmd);
|
2005-04-17 06:20:36 +08:00
|
|
|
static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
|
|
|
|
static void ub_urb_complete(struct urb *urb, struct pt_regs *pt);
|
|
|
|
static void ub_scsi_action(unsigned long _dev);
|
|
|
|
static void ub_scsi_dispatch(struct ub_dev *sc);
|
|
|
|
static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
|
2005-08-15 12:16:03 +08:00
|
|
|
static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
|
2005-04-17 06:20:36 +08:00
|
|
|
static void ub_state_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd, int rc);
|
2005-07-28 02:43:51 +08:00
|
|
|
static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
|
2005-04-17 06:20:36 +08:00
|
|
|
static void ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
|
2005-07-28 02:43:51 +08:00
|
|
|
static void ub_state_stat_counted(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
|
2005-04-17 06:20:36 +08:00
|
|
|
static void ub_state_sense(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 void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd);
|
2006-01-05 16:26:30 +08:00
|
|
|
static void ub_reset_enter(struct ub_dev *sc, int try);
|
2005-12-17 18:16:43 +08:00
|
|
|
static void ub_reset_task(void *arg);
|
2005-05-02 07:05:40 +08:00
|
|
|
static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun);
|
|
|
|
static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
|
|
|
|
struct ub_capacity *ret);
|
2006-01-05 16:26:30 +08:00
|
|
|
static int ub_sync_reset(struct ub_dev *sc);
|
|
|
|
static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe);
|
2005-05-02 07:05:40 +08:00
|
|
|
static int ub_probe_lun(struct ub_dev *sc, int lnum);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
*/
|
2005-10-23 11:15:09 +08:00
|
|
|
#ifdef CONFIG_USB_LIBUSUAL
|
|
|
|
|
|
|
|
#define ub_usb_ids storage_usb_ids
|
|
|
|
#else
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
static struct usb_device_id ub_usb_ids[] = {
|
|
|
|
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_BULK) },
|
|
|
|
{ }
|
|
|
|
};
|
|
|
|
|
|
|
|
MODULE_DEVICE_TABLE(usb, ub_usb_ids);
|
2005-10-23 11:15:09 +08:00
|
|
|
#endif /* CONFIG_USB_LIBUSUAL */
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Find me a way to identify "next free minor" for add_disk(),
|
|
|
|
* and the array disappears the next day. However, the number of
|
|
|
|
* hosts has something to do with the naming and /proc/partitions.
|
|
|
|
* This has to be thought out in detail before changing.
|
|
|
|
* If UB_MAX_HOST was 1000, we'd use a bitmap. Or a better data structure.
|
|
|
|
*/
|
|
|
|
#define UB_MAX_HOSTS 26
|
|
|
|
static char ub_hostv[UB_MAX_HOSTS];
|
2005-05-02 07:05:40 +08:00
|
|
|
|
2005-12-29 06:22:17 +08:00
|
|
|
#define UB_QLOCK_NUM 5
|
|
|
|
static spinlock_t ub_qlockv[UB_QLOCK_NUM];
|
|
|
|
static int ub_qlock_next = 0;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
static DEFINE_SPINLOCK(ub_lock); /* Locks globals and ->openc */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The id allocator.
|
|
|
|
*
|
|
|
|
* This also stores the host for indexing by minor, which is somewhat dirty.
|
|
|
|
*/
|
|
|
|
static int ub_id_get(void)
|
|
|
|
{
|
|
|
|
unsigned long flags;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
spin_lock_irqsave(&ub_lock, flags);
|
|
|
|
for (i = 0; i < UB_MAX_HOSTS; i++) {
|
|
|
|
if (ub_hostv[i] == 0) {
|
|
|
|
ub_hostv[i] = 1;
|
|
|
|
spin_unlock_irqrestore(&ub_lock, flags);
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
spin_unlock_irqrestore(&ub_lock, flags);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ub_id_put(int id)
|
|
|
|
{
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
if (id < 0 || id >= UB_MAX_HOSTS) {
|
|
|
|
printk(KERN_ERR DRV_NAME ": bad host ID %d\n", id);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
spin_lock_irqsave(&ub_lock, flags);
|
|
|
|
if (ub_hostv[id] == 0) {
|
|
|
|
spin_unlock_irqrestore(&ub_lock, flags);
|
|
|
|
printk(KERN_ERR DRV_NAME ": freeing free host ID %d\n", id);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ub_hostv[id] = 0;
|
|
|
|
spin_unlock_irqrestore(&ub_lock, flags);
|
|
|
|
}
|
|
|
|
|
2005-12-29 06:22:17 +08:00
|
|
|
/*
|
|
|
|
* This is necessitated by the fact that blk_cleanup_queue does not
|
|
|
|
* necesserily destroy the queue. Instead, it may merely decrease q->refcnt.
|
|
|
|
* Since our blk_init_queue() passes a spinlock common with ub_dev,
|
|
|
|
* we have life time issues when ub_cleanup frees ub_dev.
|
|
|
|
*/
|
|
|
|
static spinlock_t *ub_next_lock(void)
|
|
|
|
{
|
|
|
|
unsigned long flags;
|
|
|
|
spinlock_t *ret;
|
|
|
|
|
|
|
|
spin_lock_irqsave(&ub_lock, flags);
|
|
|
|
ret = &ub_qlockv[ub_qlock_next];
|
|
|
|
ub_qlock_next = (ub_qlock_next + 1) % UB_QLOCK_NUM;
|
|
|
|
spin_unlock_irqrestore(&ub_lock, flags);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* Downcount for deallocation. This rides on two assumptions:
|
|
|
|
* - once something is poisoned, its refcount cannot grow
|
|
|
|
* - opens cannot happen at this time (del_gendisk was done)
|
|
|
|
* If the above is true, we can drop the lock, which we need for
|
|
|
|
* blk_cleanup_queue(): the silly thing may attempt to sleep.
|
|
|
|
* [Actually, it never needs to sleep for us, but it calls might_sleep()]
|
|
|
|
*/
|
|
|
|
static void ub_put(struct ub_dev *sc)
|
|
|
|
{
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
spin_lock_irqsave(&ub_lock, flags);
|
|
|
|
--sc->openc;
|
|
|
|
if (sc->openc == 0 && atomic_read(&sc->poison)) {
|
|
|
|
spin_unlock_irqrestore(&ub_lock, flags);
|
|
|
|
ub_cleanup(sc);
|
|
|
|
} else {
|
|
|
|
spin_unlock_irqrestore(&ub_lock, flags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Final cleanup and deallocation.
|
|
|
|
*/
|
|
|
|
static void ub_cleanup(struct ub_dev *sc)
|
|
|
|
{
|
2005-05-02 07:05:40 +08:00
|
|
|
struct list_head *p;
|
|
|
|
struct ub_lun *lun;
|
2005-04-17 06:20:36 +08:00
|
|
|
request_queue_t *q;
|
|
|
|
|
2005-05-02 07:05:40 +08:00
|
|
|
while (!list_empty(&sc->luns)) {
|
|
|
|
p = sc->luns.next;
|
|
|
|
lun = list_entry(p, struct ub_lun, link);
|
|
|
|
list_del(p);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-05-02 07:05:40 +08:00
|
|
|
/* I don't think queue can be NULL. But... Stolen from sx8.c */
|
|
|
|
if ((q = lun->disk->queue) != NULL)
|
|
|
|
blk_cleanup_queue(q);
|
|
|
|
/*
|
|
|
|
* If we zero disk->private_data BEFORE put_disk, we have
|
|
|
|
* to check for NULL all over the place in open, release,
|
|
|
|
* check_media and revalidate, because the block level
|
|
|
|
* semaphore is well inside the put_disk.
|
|
|
|
* But we cannot zero after the call, because *disk is gone.
|
|
|
|
* The sd.c is blatantly racy in this area.
|
|
|
|
*/
|
|
|
|
/* disk->private_data = NULL; */
|
|
|
|
put_disk(lun->disk);
|
|
|
|
lun->disk = NULL;
|
|
|
|
|
|
|
|
ub_id_put(lun->id);
|
|
|
|
kfree(lun);
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
kfree(sc);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The "command allocator".
|
|
|
|
*/
|
2005-05-02 07:05:40 +08:00
|
|
|
static struct ub_scsi_cmd *ub_get_cmd(struct ub_lun *lun)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
struct ub_scsi_cmd *ret;
|
|
|
|
|
2005-05-02 07:05:40 +08:00
|
|
|
if (lun->cmda[0])
|
2005-04-17 06:20:36 +08:00
|
|
|
return NULL;
|
2005-05-02 07:05:40 +08:00
|
|
|
ret = &lun->cmdv[0];
|
|
|
|
lun->cmda[0] = 1;
|
2005-04-17 06:20:36 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2005-05-02 07:05:40 +08:00
|
|
|
static void ub_put_cmd(struct ub_lun *lun, struct ub_scsi_cmd *cmd)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2005-05-02 07:05:40 +08:00
|
|
|
if (cmd != &lun->cmdv[0]) {
|
2005-04-17 06:20:36 +08:00
|
|
|
printk(KERN_WARNING "%s: releasing a foreign cmd %p\n",
|
2005-05-02 07:05:40 +08:00
|
|
|
lun->name, cmd);
|
2005-04-17 06:20:36 +08:00
|
|
|
return;
|
|
|
|
}
|
2005-05-02 07:05:40 +08:00
|
|
|
if (!lun->cmda[0]) {
|
|
|
|
printk(KERN_WARNING "%s: releasing a free cmd\n", lun->name);
|
2005-04-17 06:20:36 +08:00
|
|
|
return;
|
|
|
|
}
|
2005-05-02 07:05:40 +08:00
|
|
|
lun->cmda[0] = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The command queue.
|
|
|
|
*/
|
|
|
|
static void ub_cmdq_add(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
|
|
|
{
|
|
|
|
struct ub_scsi_cmd_queue *t = &sc->cmd_queue;
|
|
|
|
|
|
|
|
if (t->qlen++ == 0) {
|
|
|
|
t->head = cmd;
|
|
|
|
t->tail = cmd;
|
|
|
|
} else {
|
|
|
|
t->tail->next = cmd;
|
|
|
|
t->tail = cmd;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (t->qlen > t->qmax)
|
|
|
|
t->qmax = t->qlen;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ub_cmdq_insert(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
|
|
|
{
|
|
|
|
struct ub_scsi_cmd_queue *t = &sc->cmd_queue;
|
|
|
|
|
|
|
|
if (t->qlen++ == 0) {
|
|
|
|
t->head = cmd;
|
|
|
|
t->tail = cmd;
|
|
|
|
} else {
|
|
|
|
cmd->next = t->head;
|
|
|
|
t->head = cmd;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (t->qlen > t->qmax)
|
|
|
|
t->qmax = t->qlen;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct ub_scsi_cmd *ub_cmdq_pop(struct ub_dev *sc)
|
|
|
|
{
|
|
|
|
struct ub_scsi_cmd_queue *t = &sc->cmd_queue;
|
|
|
|
struct ub_scsi_cmd *cmd;
|
|
|
|
|
|
|
|
if (t->qlen == 0)
|
|
|
|
return NULL;
|
|
|
|
if (--t->qlen == 0)
|
|
|
|
t->tail = NULL;
|
|
|
|
cmd = t->head;
|
|
|
|
t->head = cmd->next;
|
|
|
|
cmd->next = NULL;
|
|
|
|
return cmd;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define ub_cmdq_peek(sc) ((sc)->cmd_queue.head)
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The request function is our main entry point
|
|
|
|
*/
|
|
|
|
|
2005-07-31 13:51:52 +08:00
|
|
|
static void ub_request_fn(request_queue_t *q)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2005-05-02 07:05:40 +08:00
|
|
|
struct ub_lun *lun = q->queuedata;
|
2005-04-17 06:20:36 +08:00
|
|
|
struct request *rq;
|
|
|
|
|
|
|
|
while ((rq = elv_next_request(q)) != NULL) {
|
2005-07-31 13:51:52 +08:00
|
|
|
if (ub_request_fn_1(lun, rq) != 0) {
|
2005-04-17 06:20:36 +08:00
|
|
|
blk_stop_queue(q);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-07-31 13:51:52 +08:00
|
|
|
static int ub_request_fn_1(struct ub_lun *lun, struct request *rq)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2005-05-02 07:05:40 +08:00
|
|
|
struct ub_dev *sc = lun->udev;
|
2005-04-17 06:20:36 +08:00
|
|
|
struct ub_scsi_cmd *cmd;
|
2005-12-17 18:16:43 +08:00
|
|
|
struct ub_request *urq;
|
|
|
|
int n_elem;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-05-02 07:05:40 +08:00
|
|
|
if (atomic_read(&sc->poison) || lun->changed) {
|
2005-04-17 06:20:36 +08:00
|
|
|
blkdev_dequeue_request(rq);
|
|
|
|
ub_end_rq(rq, 0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-12-17 18:16:43 +08:00
|
|
|
if (lun->urq.rq != NULL)
|
|
|
|
return -1;
|
2005-05-02 07:05:40 +08:00
|
|
|
if ((cmd = ub_get_cmd(lun)) == NULL)
|
2005-04-17 06:20:36 +08:00
|
|
|
return -1;
|
|
|
|
memset(cmd, 0, sizeof(struct ub_scsi_cmd));
|
|
|
|
|
|
|
|
blkdev_dequeue_request(rq);
|
2005-12-17 18:16:43 +08:00
|
|
|
|
|
|
|
urq = &lun->urq;
|
|
|
|
memset(urq, 0, sizeof(struct ub_request));
|
|
|
|
urq->rq = rq;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* get scatterlist from block layer
|
|
|
|
*/
|
|
|
|
n_elem = blk_rq_map_sg(lun->disk->queue, rq, &urq->sgv[0]);
|
|
|
|
if (n_elem < 0) {
|
|
|
|
printk(KERN_INFO "%s: failed request map (%d)\n",
|
|
|
|
lun->name, n_elem); /* P3 */
|
|
|
|
goto drop;
|
|
|
|
}
|
|
|
|
if (n_elem > UB_MAX_REQ_SG) { /* Paranoia */
|
|
|
|
printk(KERN_WARNING "%s: request with %d segments\n",
|
|
|
|
lun->name, n_elem);
|
|
|
|
goto drop;
|
|
|
|
}
|
|
|
|
urq->nsg = n_elem;
|
|
|
|
sc->sg_stat[n_elem < 5 ? n_elem : 5]++;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
if (blk_pc_request(rq)) {
|
2005-12-17 18:16:43 +08:00
|
|
|
ub_cmd_build_packet(sc, lun, cmd, urq);
|
2005-04-17 06:20:36 +08:00
|
|
|
} else {
|
2005-12-17 18:16:43 +08:00
|
|
|
ub_cmd_build_block(sc, lun, cmd, urq);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
cmd->state = UB_CMDST_INIT;
|
2005-05-02 07:05:40 +08:00
|
|
|
cmd->lun = lun;
|
2005-04-17 06:20:36 +08:00
|
|
|
cmd->done = ub_rw_cmd_done;
|
2005-12-17 18:16:43 +08:00
|
|
|
cmd->back = urq;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
cmd->tag = sc->tagcnt++;
|
2005-12-17 18:16:43 +08:00
|
|
|
if (ub_submit_scsi(sc, cmd) != 0)
|
|
|
|
goto drop;
|
|
|
|
|
|
|
|
return 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-12-17 18:16:43 +08:00
|
|
|
drop:
|
|
|
|
ub_put_cmd(lun, cmd);
|
|
|
|
ub_end_rq(rq, 0);
|
2005-04-17 06:20:36 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-12-17 18:16:43 +08:00
|
|
|
static void ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
|
|
|
|
struct ub_scsi_cmd *cmd, struct ub_request *urq)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2005-12-17 18:16:43 +08:00
|
|
|
struct request *rq = urq->rq;
|
2005-08-15 12:16:03 +08:00
|
|
|
unsigned int block, nblks;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if (rq_data_dir(rq) == WRITE)
|
2005-12-17 18:16:43 +08:00
|
|
|
cmd->dir = UB_DIR_WRITE;
|
2005-04-17 06:20:36 +08:00
|
|
|
else
|
2005-12-17 18:16:43 +08:00
|
|
|
cmd->dir = UB_DIR_READ;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-12-17 18:16:43 +08:00
|
|
|
cmd->nsg = urq->nsg;
|
|
|
|
memcpy(cmd->sgv, urq->sgv, sizeof(struct scatterlist) * cmd->nsg);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* build the command
|
|
|
|
*
|
|
|
|
* The call to blk_queue_hardsect_size() guarantees that request
|
|
|
|
* is aligned, but it is given in terms of 512 byte units, always.
|
|
|
|
*/
|
2005-08-15 12:16:03 +08:00
|
|
|
block = rq->sector >> lun->capacity.bshift;
|
|
|
|
nblks = rq->nr_sectors >> lun->capacity.bshift;
|
2005-07-31 13:38:30 +08:00
|
|
|
|
2005-12-17 18:16:43 +08:00
|
|
|
cmd->cdb[0] = (cmd->dir == UB_DIR_READ)? READ_10: WRITE_10;
|
2005-04-17 06:20:36 +08:00
|
|
|
/* 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;
|
|
|
|
cmd->cdb[7] = nblks >> 8;
|
|
|
|
cmd->cdb[8] = nblks;
|
|
|
|
cmd->cdb_len = 10;
|
|
|
|
|
2005-08-15 12:16:03 +08:00
|
|
|
cmd->len = rq->nr_sectors * 512;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2005-12-17 18:16:43 +08:00
|
|
|
static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
|
|
|
|
struct ub_scsi_cmd *cmd, struct ub_request *urq)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
2005-12-17 18:16:43 +08:00
|
|
|
struct request *rq = urq->rq;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if (rq->data_len == 0) {
|
|
|
|
cmd->dir = UB_DIR_NONE;
|
|
|
|
} else {
|
|
|
|
if (rq_data_dir(rq) == WRITE)
|
|
|
|
cmd->dir = UB_DIR_WRITE;
|
|
|
|
else
|
|
|
|
cmd->dir = UB_DIR_READ;
|
|
|
|
}
|
2005-08-15 12:16:03 +08:00
|
|
|
|
2005-12-17 18:16:43 +08:00
|
|
|
cmd->nsg = urq->nsg;
|
|
|
|
memcpy(cmd->sgv, urq->sgv, sizeof(struct scatterlist) * cmd->nsg);
|
2005-08-15 12:16:03 +08:00
|
|
|
|
|
|
|
memcpy(&cmd->cdb, rq->cmd, rq->cmd_len);
|
|
|
|
cmd->cdb_len = rq->cmd_len;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
cmd->len = rq->data_len;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
|
|
|
{
|
2005-05-02 07:05:40 +08:00
|
|
|
struct ub_lun *lun = cmd->lun;
|
2005-12-17 18:16:43 +08:00
|
|
|
struct ub_request *urq = cmd->back;
|
|
|
|
struct request *rq;
|
2005-04-17 06:20:36 +08:00
|
|
|
int uptodate;
|
|
|
|
|
2005-12-17 18:16:43 +08:00
|
|
|
rq = urq->rq;
|
|
|
|
|
2005-08-15 12:16:03 +08:00
|
|
|
if (cmd->error == 0) {
|
2005-04-17 06:20:36 +08:00
|
|
|
uptodate = 1;
|
|
|
|
|
2005-08-15 12:16:03 +08:00
|
|
|
if (blk_pc_request(rq)) {
|
|
|
|
if (cmd->act_len >= rq->data_len)
|
|
|
|
rq->data_len = 0;
|
|
|
|
else
|
|
|
|
rq->data_len -= cmd->act_len;
|
2005-07-31 13:38:30 +08:00
|
|
|
}
|
2005-08-15 12:16:03 +08:00
|
|
|
} else {
|
2005-07-31 13:38:30 +08:00
|
|
|
uptodate = 0;
|
|
|
|
|
2005-08-15 12:16:03 +08:00
|
|
|
if (blk_pc_request(rq)) {
|
|
|
|
/* UB_SENSE_SIZE is smaller than SCSI_SENSE_BUFFERSIZE */
|
|
|
|
memcpy(rq->sense, sc->top_sense, UB_SENSE_SIZE);
|
|
|
|
rq->sense_len = UB_SENSE_SIZE;
|
|
|
|
if (sc->top_sense[0] != 0)
|
|
|
|
rq->errors = SAM_STAT_CHECK_CONDITION;
|
|
|
|
else
|
|
|
|
rq->errors = DID_ERROR << 16;
|
2005-12-17 18:16:43 +08:00
|
|
|
} else {
|
|
|
|
if (cmd->error == -EIO) {
|
|
|
|
if (ub_rw_cmd_retry(sc, lun, urq, cmd) == 0)
|
|
|
|
return;
|
|
|
|
}
|
2005-08-15 12:16:03 +08:00
|
|
|
}
|
|
|
|
}
|
2005-07-31 13:38:30 +08:00
|
|
|
|
2005-12-17 18:16:43 +08:00
|
|
|
urq->rq = NULL;
|
|
|
|
|
2005-05-02 07:05:40 +08:00
|
|
|
ub_put_cmd(lun, cmd);
|
2005-04-17 06:20:36 +08:00
|
|
|
ub_end_rq(rq, uptodate);
|
2005-07-31 13:38:30 +08:00
|
|
|
blk_start_queue(lun->disk->queue);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void ub_end_rq(struct request *rq, int uptodate)
|
|
|
|
{
|
2005-12-17 18:38:46 +08:00
|
|
|
end_that_request_first(rq, uptodate, rq->hard_nr_sectors);
|
2006-01-06 16:49:03 +08:00
|
|
|
end_that_request_last(rq, uptodate);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
2005-12-17 18:16:43 +08:00
|
|
|
static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun,
|
|
|
|
struct ub_request *urq, struct ub_scsi_cmd *cmd)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (atomic_read(&sc->poison))
|
|
|
|
return -ENXIO;
|
|
|
|
|
2006-01-05 16:26:30 +08:00
|
|
|
ub_reset_enter(sc, urq->current_try);
|
2005-12-17 18:16:43 +08:00
|
|
|
|
|
|
|
if (urq->current_try >= 3)
|
|
|
|
return -EIO;
|
|
|
|
urq->current_try++;
|
|
|
|
/* P3 */ printk("%s: dir %c len/act %d/%d "
|
|
|
|
"[sense %x %02x %02x] retry %d\n",
|
|
|
|
sc->name, UB_DIR_CHAR(cmd->dir), cmd->len, cmd->act_len,
|
|
|
|
cmd->key, cmd->asc, cmd->ascq, urq->current_try);
|
|
|
|
|
|
|
|
memset(cmd, 0, sizeof(struct ub_scsi_cmd));
|
|
|
|
ub_cmd_build_block(sc, lun, cmd, urq);
|
|
|
|
|
|
|
|
cmd->state = UB_CMDST_INIT;
|
|
|
|
cmd->lun = lun;
|
|
|
|
cmd->done = ub_rw_cmd_done;
|
|
|
|
cmd->back = urq;
|
|
|
|
|
|
|
|
cmd->tag = sc->tagcnt++;
|
|
|
|
|
|
|
|
#if 0 /* Wasteful */
|
|
|
|
return ub_submit_scsi(sc, cmd);
|
|
|
|
#else
|
|
|
|
ub_cmdq_add(sc, cmd);
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* Submit a regular SCSI operation (not an auto-sense).
|
|
|
|
*
|
|
|
|
* The Iron Law of Good Submit Routine is:
|
|
|
|
* Zero return - callback is done, Nonzero return - callback is not done.
|
|
|
|
* No exceptions.
|
|
|
|
*
|
|
|
|
* Host is assumed locked.
|
|
|
|
*/
|
|
|
|
static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (cmd->state != UB_CMDST_INIT ||
|
|
|
|
(cmd->dir != UB_DIR_NONE && cmd->len == 0)) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ub_cmdq_add(sc, cmd);
|
|
|
|
/*
|
|
|
|
* We can call ub_scsi_dispatch(sc) right away here, but it's a little
|
|
|
|
* safer to jump to a tasklet, in case upper layers do something silly.
|
|
|
|
*/
|
|
|
|
tasklet_schedule(&sc->tasklet);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Submit the first URB for the queued command.
|
|
|
|
* This function does not deal with queueing in any way.
|
|
|
|
*/
|
|
|
|
static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
|
|
|
{
|
|
|
|
struct bulk_cb_wrap *bcb;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
bcb = &sc->work_bcb;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ``If the allocation length is eighteen or greater, and a device
|
|
|
|
* server returns less than eithteen bytes of data, the application
|
|
|
|
* client should assume that the bytes not transferred would have been
|
|
|
|
* zeroes had the device server returned those bytes.''
|
|
|
|
*
|
|
|
|
* We zero sense for all commands so that when a packet request
|
|
|
|
* fails it does not return a stale sense.
|
|
|
|
*/
|
|
|
|
memset(&sc->top_sense, 0, UB_SENSE_SIZE);
|
|
|
|
|
|
|
|
/* set up the command wrapper */
|
|
|
|
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
|
|
|
|
bcb->Tag = cmd->tag; /* Endianness is not important */
|
|
|
|
bcb->DataTransferLength = cpu_to_le32(cmd->len);
|
|
|
|
bcb->Flags = (cmd->dir == UB_DIR_READ) ? 0x80 : 0;
|
2005-05-02 07:05:40 +08:00
|
|
|
bcb->Lun = (cmd->lun != NULL) ? cmd->lun->num : 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
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;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Timeout handler.
|
|
|
|
*/
|
|
|
|
static void ub_urb_timeout(unsigned long arg)
|
|
|
|
{
|
|
|
|
struct ub_dev *sc = (struct ub_dev *) arg;
|
|
|
|
unsigned long flags;
|
|
|
|
|
2005-12-29 06:22:17 +08:00
|
|
|
spin_lock_irqsave(sc->lock, flags);
|
[PATCH] USB: ub 04 Loss of timer and a hang
If SCSI commands are submitted while other commands are still processed,
the dispatch loop turns, and we stop the work_timer. Then, if URB fails
to complete, ub hangs until the device is unplugged.
This does not happen often, becase we only allow one SCSI command per
block device, but does happen (on multi-LUN devices, for example).
The fix is to stop timer only when we actually going to change the state.
The nicest code would be to have the timer stopped in URB callback, but
this is impossible, because it can be called from inside a timer, through
the urb_unlink. Then we get BUG in timer.c:cascade(). So, we do it a
little dirtier.
Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2006-01-05 16:14:02 +08:00
|
|
|
if (!ub_is_completed(&sc->work_done))
|
|
|
|
usb_unlink_urb(&sc->work_urb);
|
2005-12-29 06:22:17 +08:00
|
|
|
spin_unlock_irqrestore(sc->lock, flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
|
2005-12-29 06:22:17 +08:00
|
|
|
spin_lock_irqsave(sc->lock, flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
ub_scsi_dispatch(sc);
|
2005-12-29 06:22:17 +08:00
|
|
|
spin_unlock_irqrestore(sc->lock, flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void ub_scsi_dispatch(struct ub_dev *sc)
|
|
|
|
{
|
|
|
|
struct ub_scsi_cmd *cmd;
|
|
|
|
int rc;
|
|
|
|
|
2005-12-17 18:16:43 +08:00
|
|
|
while (!sc->reset && (cmd = ub_cmdq_peek(sc)) != NULL) {
|
2005-04-17 06:20:36 +08:00
|
|
|
if (cmd->state == UB_CMDST_DONE) {
|
|
|
|
ub_cmdq_pop(sc);
|
|
|
|
(*cmd->done)(sc, cmd);
|
|
|
|
} else if (cmd->state == UB_CMDST_INIT) {
|
|
|
|
if ((rc = ub_scsi_cmd_start(sc, cmd)) == 0)
|
|
|
|
break;
|
|
|
|
cmd->error = rc;
|
|
|
|
cmd->state = UB_CMDST_DONE;
|
|
|
|
} else {
|
|
|
|
if (!ub_is_completed(&sc->work_done))
|
|
|
|
break;
|
[PATCH] USB: ub 04 Loss of timer and a hang
If SCSI commands are submitted while other commands are still processed,
the dispatch loop turns, and we stop the work_timer. Then, if URB fails
to complete, ub hangs until the device is unplugged.
This does not happen often, becase we only allow one SCSI command per
block device, but does happen (on multi-LUN devices, for example).
The fix is to stop timer only when we actually going to change the state.
The nicest code would be to have the timer stopped in URB callback, but
this is impossible, because it can be called from inside a timer, through
the urb_unlink. Then we get BUG in timer.c:cascade(). So, we do it a
little dirtier.
Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2006-01-05 16:14:02 +08:00
|
|
|
del_timer(&sc->work_timer);
|
2005-04-17 06:20:36 +08:00
|
|
|
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;
|
2005-12-17 18:16:43 +08:00
|
|
|
int len;
|
2005-04-17 06:20:36 +08:00
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (atomic_read(&sc->poison)) {
|
2005-12-17 18:16:43 +08:00
|
|
|
ub_state_done(sc, cmd, -ENODEV);
|
|
|
|
return;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (cmd->state == UB_CMDST_CLEAR) {
|
|
|
|
if (urb->status == -EPIPE) {
|
|
|
|
/*
|
|
|
|
* STALL while clearning STALL.
|
|
|
|
* The control pipe clears itself - nothing to do.
|
|
|
|
*/
|
2005-05-02 07:05:40 +08:00
|
|
|
printk(KERN_NOTICE "%s: stall on control pipe\n",
|
|
|
|
sc->name);
|
2005-04-17 06:20:36 +08:00
|
|
|
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) {
|
2005-05-02 07:05:40 +08:00
|
|
|
printk(KERN_NOTICE "%s: stall on control pipe\n",
|
|
|
|
sc->name);
|
2005-04-17 06:20:36 +08:00
|
|
|
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);
|
|
|
|
|
2005-07-28 02:43:51 +08:00
|
|
|
} else if (cmd->state == UB_CMDST_CLRRS) {
|
|
|
|
if (urb->status == -EPIPE) {
|
|
|
|
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);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
} else if (cmd->state == UB_CMDST_CMD) {
|
2005-12-17 18:16:43 +08:00
|
|
|
switch (urb->status) {
|
|
|
|
case 0:
|
|
|
|
break;
|
|
|
|
case -EOVERFLOW:
|
|
|
|
goto Bad_End;
|
|
|
|
case -EPIPE:
|
2005-04-17 06:20:36 +08:00
|
|
|
rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe);
|
|
|
|
if (rc != 0) {
|
|
|
|
printk(KERN_NOTICE "%s: "
|
2005-05-02 07:05:40 +08:00
|
|
|
"unable to submit clear (%d)\n",
|
|
|
|
sc->name, rc);
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* This is typically ENOMEM or some other such shit.
|
|
|
|
* Retrying is pointless. Just do Bad End on it...
|
|
|
|
*/
|
2005-12-17 18:16:43 +08:00
|
|
|
ub_state_done(sc, cmd, rc);
|
|
|
|
return;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
cmd->state = UB_CMDST_CLEAR;
|
|
|
|
return;
|
2005-12-17 18:16:43 +08:00
|
|
|
case -ESHUTDOWN: /* unplug */
|
|
|
|
case -EILSEQ: /* unplug timeout on uhci */
|
|
|
|
ub_state_done(sc, cmd, -ENODEV);
|
|
|
|
return;
|
|
|
|
default:
|
2005-04-17 06:20:36 +08:00
|
|
|
goto Bad_End;
|
|
|
|
}
|
|
|
|
if (urb->actual_length != US_BULK_CB_WRAP_LEN) {
|
|
|
|
goto Bad_End;
|
|
|
|
}
|
|
|
|
|
2005-08-15 12:16:03 +08:00
|
|
|
if (cmd->dir == UB_DIR_NONE || cmd->nsg < 1) {
|
2005-04-17 06:20:36 +08:00
|
|
|
ub_state_stat(sc, cmd);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-08-15 12:16:03 +08:00
|
|
|
// udelay(125); // usb-storage has this
|
|
|
|
ub_data_start(sc, cmd);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
} 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: "
|
2005-05-02 07:05:40 +08:00
|
|
|
"unable to submit clear (%d)\n",
|
|
|
|
sc->name, rc);
|
2005-12-17 18:16:43 +08:00
|
|
|
ub_state_done(sc, cmd, rc);
|
|
|
|
return;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
cmd->state = UB_CMDST_CLR2STS;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (urb->status == -EOVERFLOW) {
|
|
|
|
/*
|
|
|
|
* A babble? Failure, but we must transfer CSW now.
|
|
|
|
*/
|
|
|
|
cmd->error = -EOVERFLOW; /* A cheap trick... */
|
2005-08-15 12:16:03 +08:00
|
|
|
ub_state_stat(sc, cmd);
|
|
|
|
return;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2005-12-17 18:16:43 +08:00
|
|
|
|
|
|
|
if (cmd->dir == UB_DIR_WRITE) {
|
|
|
|
/*
|
|
|
|
* Do not continue writes in case of a failure.
|
|
|
|
* Doing so would cause sectors to be mixed up,
|
|
|
|
* which is worse than sectors lost.
|
|
|
|
*
|
|
|
|
* We must try to read the CSW, or many devices
|
|
|
|
* get confused.
|
|
|
|
*/
|
|
|
|
len = urb->actual_length;
|
|
|
|
if (urb->status != 0 ||
|
|
|
|
len != cmd->sgv[cmd->current_sg].length) {
|
|
|
|
cmd->act_len += len;
|
|
|
|
|
|
|
|
cmd->error = -EIO;
|
|
|
|
ub_state_stat(sc, cmd);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* If an error occurs on read, we record it, and
|
|
|
|
* continue to fetch data in order to avoid bubble.
|
|
|
|
*
|
|
|
|
* As a small shortcut, we stop if we detect that
|
|
|
|
* a CSW mixed into data.
|
|
|
|
*/
|
|
|
|
if (urb->status != 0)
|
|
|
|
cmd->error = -EIO;
|
|
|
|
|
|
|
|
len = urb->actual_length;
|
|
|
|
if (urb->status != 0 ||
|
|
|
|
len != cmd->sgv[cmd->current_sg].length) {
|
|
|
|
if ((len & 0x1FF) == US_BULK_CS_WRAP_LEN)
|
|
|
|
goto Bad_End;
|
|
|
|
}
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-08-15 12:16:03 +08:00
|
|
|
cmd->act_len += urb->actual_length;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-08-15 12:16:03 +08:00
|
|
|
if (++cmd->current_sg < cmd->nsg) {
|
|
|
|
ub_data_start(sc, cmd);
|
|
|
|
return;
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
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: "
|
2005-05-02 07:05:40 +08:00
|
|
|
"unable to submit clear (%d)\n",
|
|
|
|
sc->name, rc);
|
2005-12-17 18:16:43 +08:00
|
|
|
ub_state_done(sc, cmd, rc);
|
|
|
|
return;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
2005-07-28 02:43:51 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
2005-04-17 06:20:36 +08:00
|
|
|
return;
|
|
|
|
}
|
2005-12-17 18:16:43 +08:00
|
|
|
|
|
|
|
/* Catch everything, including -EOVERFLOW and other nasties. */
|
2005-04-17 06:20:36 +08:00
|
|
|
if (urb->status != 0)
|
|
|
|
goto Bad_End;
|
|
|
|
|
|
|
|
if (urb->actual_length == 0) {
|
2005-07-28 02:43:51 +08:00
|
|
|
ub_state_stat_counted(sc, cmd);
|
2005-04-17 06:20:36 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check the returned Bulk protocol status.
|
2005-07-28 02:43:51 +08:00
|
|
|
* The status block has to be validated first.
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
bcs = &sc->work_bcs;
|
2005-07-28 02:43:51 +08:00
|
|
|
|
|
|
|
if (sc->signature == cpu_to_le32(0)) {
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
2005-07-28 02:43:51 +08:00
|
|
|
* 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.
|
2005-04-17 06:20:36 +08:00
|
|
|
*/
|
2005-07-28 02:43:51 +08:00
|
|
|
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;
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
2005-07-28 02:43:51 +08:00
|
|
|
ub_state_stat_counted(sc, cmd);
|
2005-04-17 06:20:36 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-12-17 18:16:43 +08:00
|
|
|
len = le32_to_cpu(bcs->Residue);
|
|
|
|
if (len != cmd->len - cmd->act_len) {
|
2005-07-28 02:43:51 +08:00
|
|
|
/*
|
|
|
|
* 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",
|
2005-12-17 18:16:43 +08:00
|
|
|
sc->name, len, cmd->len, cmd->act_len);
|
2005-07-28 02:43:51 +08:00
|
|
|
goto Bad_End;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
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:
|
|
|
|
/* 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);
|
2005-12-17 18:16:43 +08:00
|
|
|
ub_state_done(sc, cmd, -EINVAL);
|
|
|
|
return;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Not zeroing error to preserve a babble indicator */
|
2005-07-28 02:43:51 +08:00
|
|
|
if (cmd->error != 0) {
|
|
|
|
ub_state_sense(sc, cmd);
|
|
|
|
return;
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
cmd->state = UB_CMDST_DONE;
|
|
|
|
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: "
|
2005-05-02 07:05:40 +08:00
|
|
|
"wrong command state %d\n",
|
|
|
|
sc->name, cmd->state);
|
2005-12-17 18:16:43 +08:00
|
|
|
ub_state_done(sc, cmd, -EINVAL);
|
|
|
|
return;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
Bad_End: /* Little Excel is dead */
|
|
|
|
ub_state_done(sc, cmd, -EIO);
|
|
|
|
}
|
|
|
|
|
2005-08-15 12:16:03 +08:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* 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_cmdq_pop(sc);
|
|
|
|
(*cmd->done)(sc, cmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Factorization helper for the command state machine:
|
|
|
|
* Submit a CSW read.
|
|
|
|
*/
|
2005-07-28 02:43:51 +08:00
|
|
|
static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
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);
|
2005-07-28 02:43:51 +08:00
|
|
|
return -1;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
sc->work_timer.expires = jiffies + UB_STAT_TIMEOUT;
|
|
|
|
add_timer(&sc->work_timer);
|
2005-07-28 02:43:51 +08:00
|
|
|
return 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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)
|
|
|
|
{
|
2005-07-28 02:43:51 +08:00
|
|
|
|
|
|
|
if (__ub_state_stat(sc, cmd) != 0)
|
|
|
|
return;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
cmd->stat_count = 0;
|
|
|
|
cmd->state = UB_CMDST_STAT;
|
2005-07-28 02:43:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
2005-08-15 12:16:03 +08:00
|
|
|
struct scatterlist *sg;
|
2005-04-17 06:20:36 +08:00
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (cmd->cdb[0] == REQUEST_SENSE) {
|
|
|
|
rc = -EPIPE;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
scmd = &sc->top_rqs_cmd;
|
2005-08-15 12:16:03 +08:00
|
|
|
memset(scmd, 0, sizeof(struct ub_scsi_cmd));
|
2005-04-17 06:20:36 +08:00
|
|
|
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;
|
2005-08-15 12:16:03 +08:00
|
|
|
scmd->nsg = 1;
|
|
|
|
sg = &scmd->sgv[0];
|
|
|
|
sg->page = virt_to_page(sc->top_sense);
|
2005-09-25 04:10:16 +08:00
|
|
|
sg->offset = (unsigned long)sc->top_sense & (PAGE_SIZE-1);
|
2005-08-15 12:16:03 +08:00
|
|
|
sg->length = UB_SENSE_SIZE;
|
2005-04-17 06:20:36 +08:00
|
|
|
scmd->len = UB_SENSE_SIZE;
|
2005-05-02 07:05:40 +08:00
|
|
|
scmd->lun = cmd->lun;
|
2005-04-17 06:20:36 +08:00
|
|
|
scmd->done = ub_top_sense_done;
|
|
|
|
scmd->back = cmd;
|
|
|
|
|
|
|
|
scmd->tag = sc->tagcnt++;
|
|
|
|
|
|
|
|
cmd->state = UB_CMDST_SENSE;
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2005-08-15 12:16:03 +08:00
|
|
|
unsigned char *sense = sc->top_sense;
|
2005-04-17 06:20:36 +08:00
|
|
|
struct ub_scsi_cmd *cmd;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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: "
|
2005-05-02 07:05:40 +08:00
|
|
|
"sense done for wrong command 0x%x\n",
|
|
|
|
sc->name, cmd->tag);
|
2005-04-17 06:20:36 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (cmd->state != UB_CMDST_SENSE) {
|
|
|
|
printk(KERN_WARNING "%s: "
|
2005-05-02 07:05:40 +08:00
|
|
|
"sense done with bad cmd state %d\n",
|
|
|
|
sc->name, cmd->state);
|
2005-04-17 06:20:36 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-03-03 08:42:59 +08:00
|
|
|
/*
|
|
|
|
* Ignoring scmd->act_len, because the buffer was pre-zeroed.
|
|
|
|
*/
|
2005-04-17 06:20:36 +08:00
|
|
|
cmd->key = sense[2] & 0x0F;
|
|
|
|
cmd->asc = sense[12];
|
|
|
|
cmd->ascq = sense[13];
|
|
|
|
|
|
|
|
ub_scsi_urb_compl(sc, cmd);
|
|
|
|
}
|
|
|
|
|
2005-12-17 18:16:43 +08:00
|
|
|
/*
|
|
|
|
* Reset management
|
2006-01-05 16:26:30 +08:00
|
|
|
* XXX Move usb_reset_device to khubd. Hogging kevent is not a good thing.
|
|
|
|
* XXX Make usb_sync_reset asynchronous.
|
2005-12-17 18:16:43 +08:00
|
|
|
*/
|
|
|
|
|
2006-01-05 16:26:30 +08:00
|
|
|
static void ub_reset_enter(struct ub_dev *sc, int try)
|
2005-12-17 18:16:43 +08:00
|
|
|
{
|
|
|
|
|
|
|
|
if (sc->reset) {
|
|
|
|
/* This happens often on multi-LUN devices. */
|
|
|
|
return;
|
|
|
|
}
|
2006-01-05 16:26:30 +08:00
|
|
|
sc->reset = try + 1;
|
2005-12-17 18:16:43 +08:00
|
|
|
|
|
|
|
#if 0 /* Not needed because the disconnect waits for us. */
|
|
|
|
unsigned long flags;
|
|
|
|
spin_lock_irqsave(&ub_lock, flags);
|
|
|
|
sc->openc++;
|
|
|
|
spin_unlock_irqrestore(&ub_lock, flags);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if 0 /* We let them stop themselves. */
|
|
|
|
struct list_head *p;
|
|
|
|
struct ub_lun *lun;
|
|
|
|
list_for_each(p, &sc->luns) {
|
|
|
|
lun = list_entry(p, struct ub_lun, link);
|
|
|
|
blk_stop_queue(lun->disk->queue);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
schedule_work(&sc->reset_work);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ub_reset_task(void *arg)
|
|
|
|
{
|
|
|
|
struct ub_dev *sc = arg;
|
|
|
|
unsigned long flags;
|
|
|
|
struct list_head *p;
|
|
|
|
struct ub_lun *lun;
|
|
|
|
int lkr, rc;
|
|
|
|
|
|
|
|
if (!sc->reset) {
|
|
|
|
printk(KERN_WARNING "%s: Running reset unrequested\n",
|
|
|
|
sc->name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (atomic_read(&sc->poison)) {
|
|
|
|
printk(KERN_NOTICE "%s: Not resetting disconnected device\n",
|
|
|
|
sc->name); /* P3 This floods. Remove soon. XXX */
|
2006-01-05 16:26:30 +08:00
|
|
|
} else if ((sc->reset & 1) == 0) {
|
|
|
|
ub_sync_reset(sc);
|
|
|
|
msleep(700); /* usb-storage sleeps 6s (!) */
|
|
|
|
ub_probe_clear_stall(sc, sc->recv_bulk_pipe);
|
|
|
|
ub_probe_clear_stall(sc, sc->send_bulk_pipe);
|
2005-12-17 18:16:43 +08:00
|
|
|
} else if (sc->dev->actconfig->desc.bNumInterfaces != 1) {
|
|
|
|
printk(KERN_NOTICE "%s: Not resetting multi-interface device\n",
|
|
|
|
sc->name); /* P3 This floods. Remove soon. XXX */
|
|
|
|
} else {
|
|
|
|
if ((lkr = usb_lock_device_for_reset(sc->dev, sc->intf)) < 0) {
|
|
|
|
printk(KERN_NOTICE
|
|
|
|
"%s: usb_lock_device_for_reset failed (%d)\n",
|
|
|
|
sc->name, lkr);
|
|
|
|
} else {
|
|
|
|
rc = usb_reset_device(sc->dev);
|
|
|
|
if (rc < 0) {
|
|
|
|
printk(KERN_NOTICE "%s: "
|
|
|
|
"usb_lock_device_for_reset failed (%d)\n",
|
|
|
|
sc->name, rc);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lkr)
|
|
|
|
usb_unlock_device(sc->dev);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* In theory, no commands can be running while reset is active,
|
|
|
|
* so nobody can ask for another reset, and so we do not need any
|
|
|
|
* queues of resets or anything. We do need a spinlock though,
|
|
|
|
* to interact with block layer.
|
|
|
|
*/
|
2005-12-29 06:22:17 +08:00
|
|
|
spin_lock_irqsave(sc->lock, flags);
|
2005-12-17 18:16:43 +08:00
|
|
|
sc->reset = 0;
|
|
|
|
tasklet_schedule(&sc->tasklet);
|
|
|
|
list_for_each(p, &sc->luns) {
|
|
|
|
lun = list_entry(p, struct ub_lun, link);
|
|
|
|
blk_start_queue(lun->disk->queue);
|
|
|
|
}
|
|
|
|
wake_up(&sc->reset_wait);
|
2005-12-29 06:22:17 +08:00
|
|
|
spin_unlock_irqrestore(sc->lock, flags);
|
2005-12-17 18:16:43 +08:00
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* This is called from a process context.
|
|
|
|
*/
|
2005-05-02 07:05:40 +08:00
|
|
|
static void ub_revalidate(struct ub_dev *sc, struct ub_lun *lun)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
|
2005-05-02 07:05:40 +08:00
|
|
|
lun->readonly = 0; /* XXX Query this from the device */
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-05-02 07:05:40 +08:00
|
|
|
lun->capacity.nsec = 0;
|
|
|
|
lun->capacity.bsize = 512;
|
|
|
|
lun->capacity.bshift = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-05-02 07:05:40 +08:00
|
|
|
if (ub_sync_tur(sc, lun) != 0)
|
2005-04-17 06:20:36 +08:00
|
|
|
return; /* Not ready */
|
2005-05-02 07:05:40 +08:00
|
|
|
lun->changed = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-05-02 07:05:40 +08:00
|
|
|
if (ub_sync_read_cap(sc, lun, &lun->capacity) != 0) {
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2005-05-02 07:05:40 +08:00
|
|
|
if (ub_sync_read_cap(sc, lun, &lun->capacity) != 0) {
|
|
|
|
lun->capacity.nsec = 0;
|
|
|
|
lun->capacity.bsize = 512;
|
|
|
|
lun->capacity.bshift = 0;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
2005-05-02 07:05:40 +08:00
|
|
|
struct ub_lun *lun;
|
2005-04-17 06:20:36 +08:00
|
|
|
struct ub_dev *sc;
|
|
|
|
unsigned long flags;
|
|
|
|
int rc;
|
|
|
|
|
2005-05-02 07:05:40 +08:00
|
|
|
if ((lun = disk->private_data) == NULL)
|
2005-04-17 06:20:36 +08:00
|
|
|
return -ENXIO;
|
2005-05-02 07:05:40 +08:00
|
|
|
sc = lun->udev;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
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);
|
|
|
|
|
2005-05-02 07:05:40 +08:00
|
|
|
if (lun->removable || lun->readonly)
|
2005-04-17 06:20:36 +08:00
|
|
|
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.
|
|
|
|
*/
|
2005-05-02 07:05:40 +08:00
|
|
|
if (lun->removable && lun->changed && !(filp->f_flags & O_NDELAY)) {
|
2005-04-17 06:20:36 +08:00
|
|
|
rc = -ENOMEDIUM;
|
|
|
|
goto err_open;
|
|
|
|
}
|
|
|
|
|
2005-05-02 07:05:40 +08:00
|
|
|
if (lun->readonly && (filp->f_mode & FMODE_WRITE)) {
|
2005-04-17 06:20:36 +08:00
|
|
|
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;
|
2005-05-02 07:05:40 +08:00
|
|
|
struct ub_lun *lun = disk->private_data;
|
|
|
|
struct ub_dev *sc = lun->udev;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2005-05-02 07:05:40 +08:00
|
|
|
struct ub_lun *lun = disk->private_data;
|
|
|
|
|
|
|
|
ub_revalidate(lun->udev, lun);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/* XXX Support sector size switching like in sr.c */
|
2005-05-02 07:05:40 +08:00
|
|
|
blk_queue_hardsect_size(disk->queue, lun->capacity.bsize);
|
|
|
|
set_capacity(disk, lun->capacity.nsec);
|
|
|
|
// set_disk_ro(sdkp->disk, lun->readonly);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2005-05-02 07:05:40 +08:00
|
|
|
struct ub_lun *lun = disk->private_data;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-05-02 07:05:40 +08:00
|
|
|
if (!lun->removable)
|
2005-04-17 06:20:36 +08:00
|
|
|
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.
|
|
|
|
*/
|
2005-05-02 07:05:40 +08:00
|
|
|
if (ub_sync_tur(lun->udev, lun) != 0) {
|
|
|
|
lun->changed = 1;
|
2005-04-17 06:20:36 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2005-05-02 07:05:40 +08:00
|
|
|
return lun->changed;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
2005-05-02 07:05:40 +08:00
|
|
|
static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
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;
|
2006-02-14 12:35:57 +08:00
|
|
|
if ((cmd = kzalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto err_alloc;
|
|
|
|
|
|
|
|
cmd->cdb[0] = TEST_UNIT_READY;
|
|
|
|
cmd->cdb_len = 6;
|
|
|
|
cmd->dir = UB_DIR_NONE;
|
|
|
|
cmd->state = UB_CMDST_INIT;
|
2005-05-02 07:05:40 +08:00
|
|
|
cmd->lun = lun; /* This may be NULL, but that's ok */
|
2005-04-17 06:20:36 +08:00
|
|
|
cmd->done = ub_probe_done;
|
|
|
|
cmd->back = &compl;
|
|
|
|
|
2005-12-29 06:22:17 +08:00
|
|
|
spin_lock_irqsave(sc->lock, flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
cmd->tag = sc->tagcnt++;
|
|
|
|
|
|
|
|
rc = ub_submit_scsi(sc, cmd);
|
2005-12-29 06:22:17 +08:00
|
|
|
spin_unlock_irqrestore(sc->lock, flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
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).
|
|
|
|
*/
|
2005-05-02 07:05:40 +08:00
|
|
|
static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
|
|
|
|
struct ub_capacity *ret)
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
struct ub_scsi_cmd *cmd;
|
2005-08-15 12:16:03 +08:00
|
|
|
struct scatterlist *sg;
|
2005-04-17 06:20:36 +08:00
|
|
|
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;
|
2006-02-14 12:35:57 +08:00
|
|
|
if ((cmd = kzalloc(ALLOC_SIZE, GFP_KERNEL)) == NULL)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto err_alloc;
|
|
|
|
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;
|
2005-08-15 12:16:03 +08:00
|
|
|
cmd->nsg = 1;
|
|
|
|
sg = &cmd->sgv[0];
|
|
|
|
sg->page = virt_to_page(p);
|
2005-09-25 04:10:16 +08:00
|
|
|
sg->offset = (unsigned long)p & (PAGE_SIZE-1);
|
2005-08-15 12:16:03 +08:00
|
|
|
sg->length = 8;
|
2005-04-17 06:20:36 +08:00
|
|
|
cmd->len = 8;
|
2005-05-02 07:05:40 +08:00
|
|
|
cmd->lun = lun;
|
2005-04-17 06:20:36 +08:00
|
|
|
cmd->done = ub_probe_done;
|
|
|
|
cmd->back = &compl;
|
|
|
|
|
2005-12-29 06:22:17 +08:00
|
|
|
spin_lock_irqsave(sc->lock, flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
cmd->tag = sc->tagcnt++;
|
|
|
|
|
|
|
|
rc = ub_submit_scsi(sc, cmd);
|
2005-12-29 06:22:17 +08:00
|
|
|
spin_unlock_irqrestore(sc->lock, flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2006-01-05 16:26:30 +08:00
|
|
|
/*
|
|
|
|
* Reset with a Bulk reset.
|
|
|
|
*/
|
|
|
|
static int ub_sync_reset(struct ub_dev *sc)
|
|
|
|
{
|
|
|
|
int ifnum = sc->intf->cur_altsetting->desc.bInterfaceNumber;
|
|
|
|
struct usb_ctrlrequest *cr;
|
|
|
|
struct completion compl;
|
|
|
|
struct timer_list timer;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
init_completion(&compl);
|
|
|
|
|
|
|
|
cr = &sc->work_cr;
|
|
|
|
cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
|
|
|
|
cr->bRequest = US_BULK_RESET_REQUEST;
|
|
|
|
cr->wValue = cpu_to_le16(0);
|
|
|
|
cr->wIndex = cpu_to_le16(ifnum);
|
|
|
|
cr->wLength = cpu_to_le16(0);
|
|
|
|
|
|
|
|
usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,
|
|
|
|
(unsigned char*) cr, NULL, 0, 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) {
|
|
|
|
printk(KERN_WARNING
|
|
|
|
"%s: Unable to submit a bulk reset (%d)\n", sc->name, rc);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
init_timer(&timer);
|
|
|
|
timer.function = ub_probe_timeout;
|
|
|
|
timer.data = (unsigned long) &compl;
|
|
|
|
timer.expires = jiffies + UB_CTRL_TIMEOUT;
|
|
|
|
add_timer(&timer);
|
|
|
|
|
|
|
|
wait_for_completion(&compl);
|
|
|
|
|
|
|
|
del_timer_sync(&timer);
|
|
|
|
usb_kill_urb(&sc->work_urb);
|
|
|
|
|
|
|
|
return sc->work_urb.status;
|
|
|
|
}
|
|
|
|
|
2005-05-02 07:05:40 +08:00
|
|
|
/*
|
|
|
|
* 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) {
|
2005-09-22 15:48:29 +08:00
|
|
|
printk("%s: Stall submitting GetMaxLUN, using 1 LUN\n",
|
2005-05-02 07:05:40 +08:00
|
|
|
sc->name); /* P3 */
|
|
|
|
} else {
|
2005-09-22 15:48:29 +08:00
|
|
|
printk(KERN_NOTICE
|
2005-05-02 07:05:40 +08:00
|
|
|
"%s: Unable to submit GetMaxLUN (%d)\n",
|
|
|
|
sc->name, rc);
|
|
|
|
}
|
|
|
|
goto err_submit;
|
|
|
|
}
|
|
|
|
|
|
|
|
init_timer(&timer);
|
|
|
|
timer.function = ub_probe_timeout;
|
|
|
|
timer.data = (unsigned long) &compl;
|
|
|
|
timer.expires = jiffies + UB_CTRL_TIMEOUT;
|
|
|
|
add_timer(&timer);
|
|
|
|
|
|
|
|
wait_for_completion(&compl);
|
|
|
|
|
|
|
|
del_timer_sync(&timer);
|
|
|
|
usb_kill_urb(&sc->work_urb);
|
|
|
|
|
2005-09-22 15:48:29 +08:00
|
|
|
if ((rc = sc->work_urb.status) < 0) {
|
|
|
|
if (rc == -EPIPE) {
|
|
|
|
printk("%s: Stall at GetMaxLUN, using 1 LUN\n",
|
|
|
|
sc->name); /* P3 */
|
|
|
|
} else {
|
|
|
|
printk(KERN_NOTICE
|
|
|
|
"%s: Error at GetMaxLUN (%d)\n",
|
|
|
|
sc->name, rc);
|
|
|
|
}
|
|
|
|
goto err_io;
|
|
|
|
}
|
|
|
|
|
2005-05-02 07:05:40 +08:00
|
|
|
if (sc->work_urb.actual_length != 1) {
|
|
|
|
printk("%s: GetMaxLUN returned %d bytes\n", sc->name,
|
|
|
|
sc->work_urb.actual_length); /* P3 */
|
|
|
|
nluns = 0;
|
|
|
|
} else {
|
|
|
|
if ((nluns = *p) == 55) {
|
|
|
|
nluns = 0;
|
|
|
|
} else {
|
|
|
|
/* GetMaxLUN returns the maximum LUN number */
|
|
|
|
nluns += 1;
|
|
|
|
if (nluns > UB_MAX_LUNS)
|
|
|
|
nluns = UB_MAX_LUNS;
|
|
|
|
}
|
|
|
|
printk("%s: GetMaxLUN returned %d, using %d LUNs\n", sc->name,
|
|
|
|
*p, nluns); /* P3 */
|
|
|
|
}
|
|
|
|
|
|
|
|
kfree(p);
|
|
|
|
return nluns;
|
|
|
|
|
2005-09-22 15:48:29 +08:00
|
|
|
err_io:
|
2005-05-02 07:05:40 +08:00
|
|
|
err_submit:
|
|
|
|
kfree(p);
|
|
|
|
err_alloc:
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* Clear initial stalls.
|
|
|
|
*/
|
|
|
|
static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe)
|
|
|
|
{
|
|
|
|
int endp;
|
|
|
|
struct usb_ctrlrequest *cr;
|
|
|
|
struct completion compl;
|
|
|
|
struct timer_list timer;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
init_completion(&compl);
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe,
|
|
|
|
(unsigned char*) cr, NULL, 0, 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) {
|
|
|
|
printk(KERN_WARNING
|
|
|
|
"%s: Unable to submit a probe clear (%d)\n", sc->name, rc);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
init_timer(&timer);
|
|
|
|
timer.function = ub_probe_timeout;
|
|
|
|
timer.data = (unsigned long) &compl;
|
|
|
|
timer.expires = jiffies + UB_CTRL_TIMEOUT;
|
|
|
|
add_timer(&timer);
|
|
|
|
|
|
|
|
wait_for_completion(&compl);
|
|
|
|
|
|
|
|
del_timer_sync(&timer);
|
|
|
|
usb_kill_urb(&sc->work_urb);
|
|
|
|
|
|
|
|
/* reset the endpoint toggle */
|
|
|
|
usb_settoggle(sc->dev, endp, usb_pipeout(sc->last_pipe), 0);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get the pipe settings.
|
|
|
|
*/
|
|
|
|
static int ub_get_pipes(struct ub_dev *sc, struct usb_device *dev,
|
|
|
|
struct usb_interface *intf)
|
|
|
|
{
|
|
|
|
struct usb_host_interface *altsetting = intf->cur_altsetting;
|
|
|
|
struct usb_endpoint_descriptor *ep_in = NULL;
|
|
|
|
struct usb_endpoint_descriptor *ep_out = NULL;
|
|
|
|
struct usb_endpoint_descriptor *ep;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find the endpoints we need.
|
|
|
|
* We are expecting a minimum of 2 endpoints - in and out (bulk).
|
|
|
|
* We will ignore any others.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < altsetting->desc.bNumEndpoints; i++) {
|
|
|
|
ep = &altsetting->endpoint[i].desc;
|
|
|
|
|
|
|
|
/* Is it a BULK endpoint? */
|
|
|
|
if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
|
|
|
|
== USB_ENDPOINT_XFER_BULK) {
|
|
|
|
/* BULK in or out? */
|
|
|
|
if (ep->bEndpointAddress & USB_DIR_IN)
|
|
|
|
ep_in = ep;
|
|
|
|
else
|
|
|
|
ep_out = ep;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ep_in == NULL || ep_out == NULL) {
|
2005-05-02 07:05:40 +08:00
|
|
|
printk(KERN_NOTICE "%s: failed endpoint check\n",
|
|
|
|
sc->name);
|
2005-12-17 18:16:43 +08:00
|
|
|
return -ENODEV;
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Calculate and store the pipe values */
|
|
|
|
sc->send_ctrl_pipe = usb_sndctrlpipe(dev, 0);
|
|
|
|
sc->recv_ctrl_pipe = usb_rcvctrlpipe(dev, 0);
|
|
|
|
sc->send_bulk_pipe = usb_sndbulkpipe(dev,
|
|
|
|
ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
|
|
|
|
sc->recv_bulk_pipe = usb_rcvbulkpipe(dev,
|
|
|
|
ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Probing is done in the process context, which allows us to cheat
|
|
|
|
* and not to build a state machine for the discovery.
|
|
|
|
*/
|
|
|
|
static int ub_probe(struct usb_interface *intf,
|
|
|
|
const struct usb_device_id *dev_id)
|
|
|
|
{
|
|
|
|
struct ub_dev *sc;
|
2005-05-02 07:05:40 +08:00
|
|
|
int nluns;
|
2005-04-17 06:20:36 +08:00
|
|
|
int rc;
|
|
|
|
int i;
|
|
|
|
|
2005-10-23 11:15:09 +08:00
|
|
|
if (usb_usual_check_type(dev_id, USB_US_TYPE_UB))
|
|
|
|
return -ENXIO;
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
rc = -ENOMEM;
|
2006-02-14 12:35:57 +08:00
|
|
|
if ((sc = kzalloc(sizeof(struct ub_dev), GFP_KERNEL)) == NULL)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto err_core;
|
2005-12-29 06:22:17 +08:00
|
|
|
sc->lock = ub_next_lock();
|
2005-05-02 07:05:40 +08:00
|
|
|
INIT_LIST_HEAD(&sc->luns);
|
2005-04-17 06:20:36 +08:00
|
|
|
usb_init_urb(&sc->work_urb);
|
|
|
|
tasklet_init(&sc->tasklet, ub_scsi_action, (unsigned long)sc);
|
|
|
|
atomic_set(&sc->poison, 0);
|
2005-12-17 18:16:43 +08:00
|
|
|
INIT_WORK(&sc->reset_work, ub_reset_task, sc);
|
|
|
|
init_waitqueue_head(&sc->reset_wait);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
init_timer(&sc->work_timer);
|
|
|
|
sc->work_timer.data = (unsigned long) sc;
|
|
|
|
sc->work_timer.function = ub_urb_timeout;
|
|
|
|
|
|
|
|
ub_init_completion(&sc->work_done);
|
|
|
|
sc->work_done.done = 1; /* A little yuk, but oh well... */
|
|
|
|
|
|
|
|
sc->dev = interface_to_usbdev(intf);
|
|
|
|
sc->intf = intf;
|
|
|
|
// sc->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
|
|
|
|
usb_set_intfdata(intf, sc);
|
|
|
|
usb_get_dev(sc->dev);
|
|
|
|
// usb_get_intf(sc->intf); /* Do we need this? */
|
|
|
|
|
2005-05-02 07:05:40 +08:00
|
|
|
snprintf(sc->name, 12, DRV_NAME "(%d.%d)",
|
|
|
|
sc->dev->bus->busnum, sc->dev->devnum);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/* XXX Verify that we can handle the device (from descriptors) */
|
|
|
|
|
2005-12-17 18:16:43 +08:00
|
|
|
if (ub_get_pipes(sc, sc->dev, intf) != 0)
|
|
|
|
goto err_dev_desc;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* At this point, all USB initialization is done, do upper layer.
|
|
|
|
* We really hate halfway initialized structures, so from the
|
|
|
|
* invariants perspective, this ub_dev is fully constructed at
|
|
|
|
* this point.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is needed to clear toggles. It is a problem only if we do
|
|
|
|
* `rmmod ub && modprobe ub` without disconnects, but we like that.
|
|
|
|
*/
|
2005-09-22 15:49:45 +08:00
|
|
|
#if 0 /* iPod Mini fails if we do this (big white iPod works) */
|
2005-04-17 06:20:36 +08:00
|
|
|
ub_probe_clear_stall(sc, sc->recv_bulk_pipe);
|
|
|
|
ub_probe_clear_stall(sc, sc->send_bulk_pipe);
|
2005-09-22 15:49:45 +08:00
|
|
|
#endif
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The way this is used by the startup code is a little specific.
|
|
|
|
* A SCSI check causes a USB stall. Our common case code sees it
|
|
|
|
* and clears the check, after which the device is ready for use.
|
|
|
|
* But if a check was not present, any command other than
|
|
|
|
* TEST_UNIT_READY ends with a lockup (including REQUEST_SENSE).
|
|
|
|
*
|
|
|
|
* If we neglect to clear the SCSI check, the first real command fails
|
|
|
|
* (which is the capacity readout). We clear that and retry, but why
|
|
|
|
* causing spurious retries for no reason.
|
|
|
|
*
|
|
|
|
* Revalidation may start with its own TEST_UNIT_READY, but that one
|
|
|
|
* has to succeed, so we clear checks with an additional one here.
|
|
|
|
* In any case it's not our business how revaliadation is implemented.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < 3; i++) { /* Retries for benh's key */
|
2005-05-02 07:05:40 +08:00
|
|
|
if ((rc = ub_sync_tur(sc, NULL)) <= 0) break;
|
2005-04-17 06:20:36 +08:00
|
|
|
if (rc != 0x6) break;
|
|
|
|
msleep(10);
|
|
|
|
}
|
|
|
|
|
2005-05-02 07:05:40 +08:00
|
|
|
nluns = 1;
|
|
|
|
for (i = 0; i < 3; i++) {
|
2006-03-03 08:53:00 +08:00
|
|
|
if ((rc = ub_sync_getmaxlun(sc)) < 0)
|
2005-05-02 07:05:40 +08:00
|
|
|
break;
|
|
|
|
if (rc != 0) {
|
|
|
|
nluns = rc;
|
|
|
|
break;
|
|
|
|
}
|
2005-06-07 04:54:59 +08:00
|
|
|
msleep(100);
|
2005-05-02 07:05:40 +08:00
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-05-02 07:05:40 +08:00
|
|
|
for (i = 0; i < nluns; i++) {
|
|
|
|
ub_probe_lun(sc, i);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
|
2005-12-17 18:16:43 +08:00
|
|
|
err_dev_desc:
|
2005-05-02 07:05:40 +08:00
|
|
|
usb_set_intfdata(intf, NULL);
|
|
|
|
// usb_put_intf(sc->intf);
|
|
|
|
usb_put_dev(sc->dev);
|
|
|
|
kfree(sc);
|
|
|
|
err_core:
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int ub_probe_lun(struct ub_dev *sc, int lnum)
|
|
|
|
{
|
|
|
|
struct ub_lun *lun;
|
|
|
|
request_queue_t *q;
|
|
|
|
struct gendisk *disk;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
rc = -ENOMEM;
|
2006-02-14 12:35:57 +08:00
|
|
|
if ((lun = kzalloc(sizeof(struct ub_lun), GFP_KERNEL)) == NULL)
|
2005-05-02 07:05:40 +08:00
|
|
|
goto err_alloc;
|
|
|
|
lun->num = lnum;
|
|
|
|
|
|
|
|
rc = -ENOSR;
|
|
|
|
if ((lun->id = ub_id_get()) == -1)
|
|
|
|
goto err_id;
|
|
|
|
|
|
|
|
lun->udev = sc;
|
|
|
|
list_add(&lun->link, &sc->luns);
|
|
|
|
|
|
|
|
snprintf(lun->name, 16, DRV_NAME "%c(%d.%d.%d)",
|
|
|
|
lun->id + 'a', sc->dev->bus->busnum, sc->dev->devnum, lun->num);
|
|
|
|
|
|
|
|
lun->removable = 1; /* XXX Query this from the device */
|
|
|
|
lun->changed = 1; /* ub_revalidate clears only */
|
|
|
|
ub_revalidate(sc, lun);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
rc = -ENOMEM;
|
2005-12-17 18:34:12 +08:00
|
|
|
if ((disk = alloc_disk(UB_PARTS_PER_LUN)) == NULL)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto err_diskalloc;
|
|
|
|
|
2005-05-02 07:05:40 +08:00
|
|
|
lun->disk = disk;
|
|
|
|
sprintf(disk->disk_name, DRV_NAME "%c", lun->id + 'a');
|
|
|
|
sprintf(disk->devfs_name, DEVFS_NAME "/%c", lun->id + 'a');
|
2005-04-17 06:20:36 +08:00
|
|
|
disk->major = UB_MAJOR;
|
2005-12-17 18:34:12 +08:00
|
|
|
disk->first_minor = lun->id * UB_PARTS_PER_LUN;
|
2005-04-17 06:20:36 +08:00
|
|
|
disk->fops = &ub_bd_fops;
|
2005-05-02 07:05:40 +08:00
|
|
|
disk->private_data = lun;
|
2005-09-22 15:48:29 +08:00
|
|
|
disk->driverfs_dev = &sc->intf->dev;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
rc = -ENOMEM;
|
2005-12-29 06:22:17 +08:00
|
|
|
if ((q = blk_init_queue(ub_request_fn, sc->lock)) == NULL)
|
2005-04-17 06:20:36 +08:00
|
|
|
goto err_blkqinit;
|
|
|
|
|
|
|
|
disk->queue = q;
|
|
|
|
|
2005-05-02 07:05:40 +08:00
|
|
|
blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH);
|
2005-04-17 06:20:36 +08:00
|
|
|
blk_queue_max_hw_segments(q, UB_MAX_REQ_SG);
|
|
|
|
blk_queue_max_phys_segments(q, UB_MAX_REQ_SG);
|
2005-05-02 07:05:40 +08:00
|
|
|
blk_queue_segment_boundary(q, 0xffffffff); /* Dubious. */
|
2005-04-17 06:20:36 +08:00
|
|
|
blk_queue_max_sectors(q, UB_MAX_SECTORS);
|
2005-05-02 07:05:40 +08:00
|
|
|
blk_queue_hardsect_size(q, lun->capacity.bsize);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-05-02 07:05:40 +08:00
|
|
|
q->queuedata = lun;
|
2005-04-17 06:20:36 +08:00
|
|
|
|
2005-05-02 07:05:40 +08:00
|
|
|
set_capacity(disk, lun->capacity.nsec);
|
|
|
|
if (lun->removable)
|
2005-04-17 06:20:36 +08:00
|
|
|
disk->flags |= GENHD_FL_REMOVABLE;
|
|
|
|
|
|
|
|
add_disk(disk);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err_blkqinit:
|
|
|
|
put_disk(disk);
|
|
|
|
err_diskalloc:
|
2005-05-02 07:05:40 +08:00
|
|
|
list_del(&lun->link);
|
|
|
|
ub_id_put(lun->id);
|
2005-04-17 06:20:36 +08:00
|
|
|
err_id:
|
2005-05-02 07:05:40 +08:00
|
|
|
kfree(lun);
|
|
|
|
err_alloc:
|
2005-04-17 06:20:36 +08:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void ub_disconnect(struct usb_interface *intf)
|
|
|
|
{
|
|
|
|
struct ub_dev *sc = usb_get_intfdata(intf);
|
2005-05-02 07:05:40 +08:00
|
|
|
struct list_head *p;
|
|
|
|
struct ub_lun *lun;
|
|
|
|
struct gendisk *disk;
|
2005-04-17 06:20:36 +08:00
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Prevent ub_bd_release from pulling the rug from under us.
|
|
|
|
* XXX This is starting to look like a kref.
|
|
|
|
* XXX Why not to take this ref at probe time?
|
|
|
|
*/
|
|
|
|
spin_lock_irqsave(&ub_lock, flags);
|
|
|
|
sc->openc++;
|
|
|
|
spin_unlock_irqrestore(&ub_lock, flags);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Fence stall clearnings, operations triggered by unlinkings and so on.
|
|
|
|
* We do not attempt to unlink any URBs, because we do not trust the
|
|
|
|
* unlink paths in HC drivers. Also, we get -84 upon disconnect anyway.
|
|
|
|
*/
|
|
|
|
atomic_set(&sc->poison, 1);
|
|
|
|
|
2005-12-17 18:16:43 +08:00
|
|
|
/*
|
|
|
|
* Wait for reset to end, if any.
|
|
|
|
*/
|
|
|
|
wait_event(sc->reset_wait, !sc->reset);
|
|
|
|
|
2005-04-17 06:20:36 +08:00
|
|
|
/*
|
|
|
|
* Blow away queued commands.
|
|
|
|
*
|
|
|
|
* Actually, this never works, because before we get here
|
|
|
|
* the HCD terminates outstanding URB(s). It causes our
|
|
|
|
* SCSI command queue to advance, commands fail to submit,
|
|
|
|
* and the whole queue drains. So, we just use this code to
|
|
|
|
* print warnings.
|
|
|
|
*/
|
2005-12-29 06:22:17 +08:00
|
|
|
spin_lock_irqsave(sc->lock, flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
{
|
|
|
|
struct ub_scsi_cmd *cmd;
|
|
|
|
int cnt = 0;
|
2005-12-17 18:16:43 +08:00
|
|
|
while ((cmd = ub_cmdq_peek(sc)) != NULL) {
|
2005-04-17 06:20:36 +08:00
|
|
|
cmd->error = -ENOTCONN;
|
|
|
|
cmd->state = UB_CMDST_DONE;
|
|
|
|
ub_cmdq_pop(sc);
|
|
|
|
(*cmd->done)(sc, cmd);
|
|
|
|
cnt++;
|
|
|
|
}
|
|
|
|
if (cnt != 0) {
|
|
|
|
printk(KERN_WARNING "%s: "
|
|
|
|
"%d was queued after shutdown\n", sc->name, cnt);
|
|
|
|
}
|
|
|
|
}
|
2005-12-29 06:22:17 +08:00
|
|
|
spin_unlock_irqrestore(sc->lock, flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Unregister the upper layer.
|
|
|
|
*/
|
2005-05-02 07:05:40 +08:00
|
|
|
list_for_each (p, &sc->luns) {
|
|
|
|
lun = list_entry(p, struct ub_lun, link);
|
|
|
|
disk = lun->disk;
|
|
|
|
if (disk->flags & GENHD_FL_UP)
|
|
|
|
del_gendisk(disk);
|
|
|
|
/*
|
|
|
|
* I wish I could do:
|
|
|
|
* set_bit(QUEUE_FLAG_DEAD, &q->queue_flags);
|
|
|
|
* As it is, we rely on our internal poisoning and let
|
|
|
|
* the upper levels to spin furiously failing all the I/O.
|
|
|
|
*/
|
|
|
|
}
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Testing for -EINPROGRESS is always a bug, so we are bending
|
|
|
|
* the rules a little.
|
|
|
|
*/
|
2005-12-29 06:22:17 +08:00
|
|
|
spin_lock_irqsave(sc->lock, flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
if (sc->work_urb.status == -EINPROGRESS) { /* janitors: ignore */
|
|
|
|
printk(KERN_WARNING "%s: "
|
|
|
|
"URB is active after disconnect\n", sc->name);
|
|
|
|
}
|
2005-12-29 06:22:17 +08:00
|
|
|
spin_unlock_irqrestore(sc->lock, flags);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* There is virtually no chance that other CPU runs times so long
|
|
|
|
* after ub_urb_complete should have called del_timer, but only if HCD
|
|
|
|
* didn't forget to deliver a callback on unlink.
|
|
|
|
*/
|
|
|
|
del_timer_sync(&sc->work_timer);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* At this point there must be no commands coming from anyone
|
|
|
|
* and no URBs left in transit.
|
|
|
|
*/
|
|
|
|
|
|
|
|
usb_set_intfdata(intf, NULL);
|
|
|
|
// usb_put_intf(sc->intf);
|
|
|
|
sc->intf = NULL;
|
|
|
|
usb_put_dev(sc->dev);
|
|
|
|
sc->dev = NULL;
|
|
|
|
|
|
|
|
ub_put(sc);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct usb_driver ub_driver = {
|
|
|
|
.name = "ub",
|
|
|
|
.probe = ub_probe,
|
|
|
|
.disconnect = ub_disconnect,
|
|
|
|
.id_table = ub_usb_ids,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int __init ub_init(void)
|
|
|
|
{
|
|
|
|
int rc;
|
2005-12-29 06:22:17 +08:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < UB_QLOCK_NUM; i++)
|
|
|
|
spin_lock_init(&ub_qlockv[i]);
|
2005-04-17 06:20:36 +08:00
|
|
|
|
|
|
|
if ((rc = register_blkdev(UB_MAJOR, DRV_NAME)) != 0)
|
|
|
|
goto err_regblkdev;
|
|
|
|
devfs_mk_dir(DEVFS_NAME);
|
|
|
|
|
|
|
|
if ((rc = usb_register(&ub_driver)) != 0)
|
|
|
|
goto err_register;
|
|
|
|
|
2005-10-23 11:15:09 +08:00
|
|
|
usb_usual_set_present(USB_US_TYPE_UB);
|
2005-04-17 06:20:36 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
err_register:
|
|
|
|
devfs_remove(DEVFS_NAME);
|
|
|
|
unregister_blkdev(UB_MAJOR, DRV_NAME);
|
|
|
|
err_regblkdev:
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __exit ub_exit(void)
|
|
|
|
{
|
|
|
|
usb_deregister(&ub_driver);
|
|
|
|
|
|
|
|
devfs_remove(DEVFS_NAME);
|
|
|
|
unregister_blkdev(UB_MAJOR, DRV_NAME);
|
2005-10-23 11:15:09 +08:00
|
|
|
usb_usual_clear_present(USB_US_TYPE_UB);
|
2005-04-17 06:20:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
module_init(ub_init);
|
|
|
|
module_exit(ub_exit);
|
|
|
|
|
|
|
|
MODULE_LICENSE("GPL");
|