/*
* Timeouts for various operations:
*/
-#define WAIT_DRQ (HZ/10) /* 100msec - spec allows up to 20ms */
-#define WAIT_READY (5*HZ) /* 5sec - some laptops are very slow */
-#define WAIT_PIDENTIFY (10*HZ) /* 10sec - should be less than 3ms (?), if all ATAPI CD is closed at boot */
-#define WAIT_WORSTCASE (30*HZ) /* 30sec - worst case when spinning up */
-#define WAIT_CMD (10*HZ) /* 10sec - maximum wait for an IRQ to happen */
-#define WAIT_MIN_SLEEP (2*HZ/100) /* 20msec - minimum sleep time */
+enum {
+ /* spec allows up to 20ms */
+ WAIT_DRQ = HZ / 10, /* 100ms */
+ /* some laptops are very slow */
+ WAIT_READY = 5 * HZ, /* 5s */
+ /* should be less than 3ms (?), if all ATAPI CD is closed at boot */
+ WAIT_PIDENTIFY = 10 * HZ, /* 10s */
+ /* worst case when spinning up */
+ WAIT_WORSTCASE = 30 * HZ, /* 30s */
+ /* maximum wait for an IRQ to happen */
+ WAIT_CMD = 10 * HZ, /* 10s */
+ /* Some drives require a longer IRQ timeout. */
+ WAIT_FLOPPY_CMD = 50 * HZ, /* 50s */
+ /*
+ * Some drives (for example, Seagate STT3401A Travan) require a very
+ * long timeout, because they don't return an interrupt or clear their
+ * BSY bit until after the command completes (even retension commands).
+ */
+ WAIT_TAPE_CMD = 900 * HZ, /* 900s */
+ /* minimum sleep time */
+ WAIT_MIN_SLEEP = HZ / 50, /* 20ms */
+};
/*
* Op codes for special requests to be handled by ide_special_rq().
* Values should be in the range of 0x20 to 0x3f.
*/
#define REQ_DRIVE_RESET 0x20
+#define REQ_DEVSET_EXEC 0x21
/*
* Check for an interrupt and acknowledge the interrupt status
ide_started, /* a drive operation was started, handler was set */
} ide_startstop_t;
+/* ATAPI packet command flags */
+enum {
+ /* set when an error is considered normal - no retry (ide-tape) */
+ PC_FLAG_ABORT = (1 << 0),
+ PC_FLAG_SUPPRESS_ERROR = (1 << 1),
+ PC_FLAG_WAIT_FOR_DSC = (1 << 2),
+ PC_FLAG_DMA_OK = (1 << 3),
+ PC_FLAG_DMA_IN_PROGRESS = (1 << 4),
+ PC_FLAG_DMA_ERROR = (1 << 5),
+ PC_FLAG_WRITING = (1 << 6),
+ /* command timed out */
+ PC_FLAG_TIMEDOUT = (1 << 7),
+};
+
+/*
+ * With each packet command, we allocate a buffer of IDE_PC_BUFFER_SIZE bytes.
+ * This is used for several packet commands (not for READ/WRITE commands).
+ */
+#define IDE_PC_BUFFER_SIZE 256
+
+struct ide_atapi_pc {
+ /* actual packet bytes */
+ u8 c[12];
+ /* incremented on each retry */
+ int retries;
+ int error;
+
+ /* bytes to transfer */
+ int req_xfer;
+ /* bytes actually transferred */
+ int xferred;
+
+ /* data buffer */
+ u8 *buf;
+ /* current buffer position */
+ u8 *cur_pos;
+ int buf_size;
+ /* missing/available data on the current buffer */
+ int b_count;
+
+ /* the corresponding request */
+ struct request *rq;
+
+ unsigned long flags;
+
+ /*
+ * those are more or less driver-specific and some of them are subject
+ * to change/removal later.
+ */
+ u8 pc_buf[IDE_PC_BUFFER_SIZE];
+
+ /* idetape only */
+ struct idetape_bh *bh;
+ char *b_data;
+
+ /* idescsi only for now */
+ struct scatterlist *sg;
+ unsigned int sg_cnt;
+
+ struct scsi_cmnd *scsi_cmd;
+ void (*done) (struct scsi_cmnd *);
+
+ unsigned long timeout;
+};
+
struct ide_devset;
struct ide_driver_s;
enum {
IDE_AFLAG_DRQ_INTERRUPT = (1 << 0),
IDE_AFLAG_MEDIA_CHANGED = (1 << 1),
-
- /* ide-cd */
/* Drive cannot lock the door. */
IDE_AFLAG_NO_DOORLOCK = (1 << 2),
+
+ /* ide-cd */
/* Drive cannot eject the disc. */
IDE_AFLAG_NO_EJECT = (1 << 3),
/* Drive is a pre ATAPI 1.2 drive. */
IDE_AFLAG_CLIK_DRIVE = (1 << 19),
/* Requires BH algorithm for packets */
IDE_AFLAG_ZIP_DRIVE = (1 << 20),
+ /* Write protect */
+ IDE_AFLAG_WP = (1 << 21),
+ /* Supports format progress report */
+ IDE_AFLAG_SRFP = (1 << 22),
/* ide-tape */
- IDE_AFLAG_IGNORE_DSC = (1 << 21),
+ IDE_AFLAG_IGNORE_DSC = (1 << 23),
/* 0 When the tape position is unknown */
- IDE_AFLAG_ADDRESS_VALID = (1 << 22),
+ IDE_AFLAG_ADDRESS_VALID = (1 << 24),
/* Device already opened */
- IDE_AFLAG_BUSY = (1 << 23),
+ IDE_AFLAG_BUSY = (1 << 25),
/* Attempt to auto-detect the current user block size */
- IDE_AFLAG_DETECT_BS = (1 << 24),
+ IDE_AFLAG_DETECT_BS = (1 << 26),
/* Currently on a filemark */
- IDE_AFLAG_FILEMARK = (1 << 25),
+ IDE_AFLAG_FILEMARK = (1 << 27),
/* 0 = no tape is loaded, so we don't rewind after ejecting */
- IDE_AFLAG_MEDIUM_PRESENT = (1 << 26),
+ IDE_AFLAG_MEDIUM_PRESENT = (1 << 28),
- IDE_AFLAG_NO_AUTOCLOSE = (1 << 27),
+ IDE_AFLAG_NO_AUTOCLOSE = (1 << 29),
};
struct ide_drive_s {
u16 *id; /* identification info */
#ifdef CONFIG_IDE_PROC_FS
struct proc_dir_entry *proc; /* /proc/ide/ directory entry */
- const struct ide_devset **settings; /* /proc/ide/ drive settings */
+ const struct ide_proc_devset *settings; /* /proc/ide/ drive settings */
#endif
struct hwif_s *hwif; /* actually (ide_hwif_t *) */
struct device gendev;
struct completion gendev_rel_comp; /* to deal with device release() */
+ /* current packet command */
+ struct ide_atapi_pc *pc;
+
/* callback for packet commands */
- void (*pc_callback)(struct ide_drive_s *);
+ void (*pc_callback)(struct ide_drive_s *, int);
+
+ void (*pc_update_buffers)(struct ide_drive_s *, struct ide_atapi_pc *);
+ int (*pc_io_buffers)(struct ide_drive_s *, struct ide_atapi_pc *,
+ unsigned int, int);
unsigned long atapi_flags;
+
+ struct ide_atapi_pc request_sense_pc;
+ struct request request_sense_rq;
};
typedef struct ide_drive_s ide_drive_t;
extern struct mutex ide_setting_mtx;
-int get_io_32bit(ide_drive_t *);
-int set_io_32bit(ide_drive_t *, int);
-int get_ksettings(ide_drive_t *);
-int set_ksettings(ide_drive_t *, int);
-int set_pio_mode(ide_drive_t *, int);
-int get_unmaskirq(ide_drive_t *);
-int set_unmaskirq(ide_drive_t *, int);
-int get_using_dma(ide_drive_t *);
-int set_using_dma(ide_drive_t *, int);
+/*
+ * configurable drive settings
+ */
+
+#define DS_SYNC (1 << 0)
+
+struct ide_devset {
+ int (*get)(ide_drive_t *);
+ int (*set)(ide_drive_t *, int);
+ unsigned int flags;
+};
+
+#define __DEVSET(_flags, _get, _set) { \
+ .flags = _flags, \
+ .get = _get, \
+ .set = _set, \
+}
#define ide_devset_get(name, field) \
-int get_##name(ide_drive_t *drive) \
+static int get_##name(ide_drive_t *drive) \
{ \
return drive->field; \
}
#define ide_devset_set(name, field) \
-int set_##name(ide_drive_t *drive, int arg) \
+static int set_##name(ide_drive_t *drive, int arg) \
{ \
drive->field = arg; \
return 0; \
}
-/* ATAPI packet command flags */
-enum {
- /* set when an error is considered normal - no retry (ide-tape) */
- PC_FLAG_ABORT = (1 << 0),
- PC_FLAG_SUPPRESS_ERROR = (1 << 1),
- PC_FLAG_WAIT_FOR_DSC = (1 << 2),
- PC_FLAG_DMA_OK = (1 << 3),
- PC_FLAG_DMA_IN_PROGRESS = (1 << 4),
- PC_FLAG_DMA_ERROR = (1 << 5),
- PC_FLAG_WRITING = (1 << 6),
- /* command timed out */
- PC_FLAG_TIMEDOUT = (1 << 7),
-};
-
-struct ide_atapi_pc {
- /* actual packet bytes */
- u8 c[12];
- /* incremented on each retry */
- int retries;
- int error;
+#define __IDE_DEVSET(_name, _flags, _get, _set) \
+const struct ide_devset ide_devset_##_name = \
+ __DEVSET(_flags, _get, _set)
- /* bytes to transfer */
- int req_xfer;
- /* bytes actually transferred */
- int xferred;
+#define IDE_DEVSET(_name, _flags, _get, _set) \
+static __IDE_DEVSET(_name, _flags, _get, _set)
- /* data buffer */
- u8 *buf;
- /* current buffer position */
- u8 *cur_pos;
- int buf_size;
- /* missing/available data on the current buffer */
- int b_count;
-
- /* the corresponding request */
- struct request *rq;
+#define ide_devset_rw(_name, _func) \
+IDE_DEVSET(_name, 0, get_##_func, set_##_func)
- unsigned long flags;
-
- /*
- * those are more or less driver-specific and some of them are subject
- * to change/removal later.
- */
- u8 pc_buf[256];
-
- /* idetape only */
- struct idetape_bh *bh;
- char *b_data;
+#define ide_devset_w(_name, _func) \
+IDE_DEVSET(_name, 0, NULL, set_##_func)
- /* idescsi only for now */
- struct scatterlist *sg;
- unsigned int sg_cnt;
+#define ide_devset_rw_sync(_name, _func) \
+IDE_DEVSET(_name, DS_SYNC, get_##_func, set_##_func)
- struct scsi_cmnd *scsi_cmd;
- void (*done) (struct scsi_cmnd *);
+#define ide_decl_devset(_name) \
+extern const struct ide_devset ide_devset_##_name
- unsigned long timeout;
-};
+ide_decl_devset(io_32bit);
+ide_decl_devset(keepsettings);
+ide_decl_devset(pio_mode);
+ide_decl_devset(unmaskirq);
+ide_decl_devset(using_dma);
#ifdef CONFIG_IDE_PROC_FS
/*
- * configurable drive settings
+ * /proc/ide interface
*/
-#define S_READ (1 << 0)
-#define S_WRITE (1 << 1)
-#define S_RW (S_READ | S_WRITE)
-#define S_NOLOCK (1 << 2)
-
-struct ide_devset {
- const char *name;
- unsigned int flags;
- int min, max;
- int (*get)(ide_drive_t *);
- int (*set)(ide_drive_t *, int);
- int (*mulf)(ide_drive_t *);
- int (*divf)(ide_drive_t *);
+#define ide_devset_rw_field(_name, _field) \
+ide_devset_get(_name, _field); \
+ide_devset_set(_name, _field); \
+IDE_DEVSET(_name, DS_SYNC, get_##_name, set_##_name)
+
+struct ide_proc_devset {
+ const char *name;
+ const struct ide_devset *setting;
+ int min, max;
+ int (*mulf)(ide_drive_t *);
+ int (*divf)(ide_drive_t *);
};
-#define __DEVSET(_name, _flags, _min, _max, _get, _set, _mulf, _divf) { \
- .name = __stringify(_name), \
- .flags = _flags, \
- .min = _min, \
- .max = _max, \
- .get = _get, \
- .set = _set, \
- .mulf = _mulf, \
- .divf = _divf, \
+#define __IDE_PROC_DEVSET(_name, _min, _max, _mulf, _divf) { \
+ .name = __stringify(_name), \
+ .setting = &ide_devset_##_name, \
+ .min = _min, \
+ .max = _max, \
+ .mulf = _mulf, \
+ .divf = _divf, \
}
-#define __IDE_DEVSET(_name, _flags, _min, _max, _get, _set, _mulf, _divf) \
-static const struct ide_devset ide_devset_##_name = \
- __DEVSET(_name, _flags, _min, _max, _get, _set, _mulf, _divf)
-
-#define IDE_DEVSET(_name, _flags, _min, _max, _get, _set) \
-__IDE_DEVSET(_name, _flags, _min, _max, _get, _set, NULL, NULL)
+#define IDE_PROC_DEVSET(_name, _min, _max) \
+__IDE_PROC_DEVSET(_name, _min, _max, NULL, NULL)
-#define ide_devset_rw_nolock(_name, _min, _max, _func) \
-IDE_DEVSET(_name, S_RW | S_NOLOCK, _min, _max, get_##_func, set_##_func)
-
-#define ide_devset_w_nolock(_name, _min, _max, _func) \
-IDE_DEVSET(_name, S_WRITE | S_NOLOCK, _min, _max, NULL, set_##_func)
-
-#define ide_devset_rw(_name, _min, _max, _field) \
-static ide_devset_get(_name, _field); \
-static ide_devset_set(_name, _field); \
-IDE_DEVSET(_name, S_RW, _min, _max, get_##_name, set_##_name)
-
-#define ide_devset_r(_name, _min, _max, _field) \
-ide_devset_get(_name, _field) \
-IDE_DEVSET(_name, S_READ, _min, _max, get_##_name, NULL)
-
-/*
- * /proc/ide interface
- */
typedef struct {
const char *name;
mode_t mode;
void (*resume)(ide_drive_t *);
void (*shutdown)(ide_drive_t *);
#ifdef CONFIG_IDE_PROC_FS
- ide_proc_entry_t *proc;
- const struct ide_devset **settings;
+ ide_proc_entry_t *proc;
+ const struct ide_proc_devset *settings;
#endif
};
struct ide_ioctl_devset {
unsigned int get_ioctl;
unsigned int set_ioctl;
-
- int (*get)(ide_drive_t *);
- int (*set)(ide_drive_t *, int);
+ const struct ide_devset *setting;
};
int ide_setting_ioctl(ide_drive_t *, struct block_device *, unsigned int,
extern ide_startstop_t ide_do_reset (ide_drive_t *);
+extern int ide_devset_execute(ide_drive_t *drive,
+ const struct ide_devset *setting, int arg);
+
extern void ide_do_drive_cmd(ide_drive_t *, struct request *);
extern void ide_end_drive_cmd(ide_drive_t *, u8, u8);
void ide_input_data(ide_drive_t *, struct request *, void *, unsigned int);
void ide_output_data(ide_drive_t *, struct request *, void *, unsigned int);
+int ide_io_buffers(ide_drive_t *, struct ide_atapi_pc *, unsigned int, int);
+
extern void SELECT_DRIVE(ide_drive_t *);
void SELECT_MASK(ide_drive_t *, int);
void ide_pktcmd_tf_load(ide_drive_t *, u32, u16, u8);
-ide_startstop_t ide_pc_intr(ide_drive_t *drive, struct ide_atapi_pc *pc,
- ide_handler_t *handler, unsigned int timeout, ide_expiry_t *expiry,
- void (*update_buffers)(ide_drive_t *, struct ide_atapi_pc *),
- void (*retry_pc)(ide_drive_t *), void (*dsc_handle)(ide_drive_t *),
- void (*io_buffers)(ide_drive_t *, struct ide_atapi_pc *, unsigned int,
- int));
-ide_startstop_t ide_transfer_pc(ide_drive_t *, struct ide_atapi_pc *,
+int ide_check_atapi_device(ide_drive_t *, const char *);
+
+void ide_init_pc(struct ide_atapi_pc *);
+
+/*
+ * Special requests for ide-tape block device strategy routine.
+ *
+ * In order to service a character device command, we add special requests to
+ * the tail of our block device request queue and wait for their completion.
+ */
+enum {
+ REQ_IDETAPE_PC1 = (1 << 0), /* packet command (first stage) */
+ REQ_IDETAPE_PC2 = (1 << 1), /* packet command (second stage) */
+ REQ_IDETAPE_READ = (1 << 2),
+ REQ_IDETAPE_WRITE = (1 << 3),
+};
+
+int ide_queue_pc_tail(ide_drive_t *, struct gendisk *, struct ide_atapi_pc *);
+
+int ide_do_test_unit_ready(ide_drive_t *, struct gendisk *);
+int ide_do_start_stop(ide_drive_t *, struct gendisk *, int);
+int ide_set_media_lock(ide_drive_t *, struct gendisk *, int);
+void ide_create_request_sense_cmd(ide_drive_t *, struct ide_atapi_pc *);
+void ide_retry_pc(ide_drive_t *, struct gendisk *);
+
+static inline unsigned long ide_scsi_get_timeout(struct ide_atapi_pc *pc)
+{
+ return max_t(unsigned long, WAIT_CMD, pc->timeout - jiffies);
+}
+
+int ide_scsi_expiry(ide_drive_t *);
+
+ide_startstop_t ide_pc_intr(ide_drive_t *drive, ide_handler_t *handler);
+ide_startstop_t ide_transfer_pc(ide_drive_t *,
ide_handler_t *, unsigned int, ide_expiry_t *);
-ide_startstop_t ide_issue_pc(ide_drive_t *, struct ide_atapi_pc *,
+ide_startstop_t ide_issue_pc(ide_drive_t *,
ide_handler_t *, unsigned int, ide_expiry_t *);
ide_startstop_t do_rw_taskfile(ide_drive_t *, ide_task_t *);
int ide_no_data_taskfile(ide_drive_t *, ide_task_t *);
int ide_taskfile_ioctl(ide_drive_t *, unsigned int, unsigned long);
-int ide_cmd_ioctl(ide_drive_t *, unsigned int, unsigned long);
-int ide_task_ioctl(ide_drive_t *, unsigned int, unsigned long);
extern int ide_driveid_update(ide_drive_t *);
extern int ide_config_drive_speed(ide_drive_t *, u8);
extern void ide_stall_queue(ide_drive_t *drive, unsigned long timeout);
-extern int ide_spin_wait_hwgroup(ide_drive_t *);
extern void ide_timer_expiry(unsigned long);
extern irqreturn_t ide_intr(int irq, void *dev_id);
extern void do_ide_request(struct request_queue *);