|
@@ -144,9 +144,6 @@ enum {
|
|
|
|
|
|
/*************************** End of tunable parameters ***********************/
|
|
|
|
|
|
-/* Read/Write error simulation */
|
|
|
-#define SIMULATE_ERRORS 0
|
|
|
-
|
|
|
/* tape directions */
|
|
|
enum {
|
|
|
IDETAPE_DIR_NONE = (1 << 0),
|
|
@@ -442,7 +439,7 @@ static void idetape_output_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void idetape_update_buffers(struct ide_atapi_pc *pc)
|
|
|
+static void idetape_update_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc)
|
|
|
{
|
|
|
struct idetape_bh *bh = pc->bh;
|
|
|
int count;
|
|
@@ -506,18 +503,6 @@ static struct request *idetape_next_rq_storage(ide_drive_t *drive)
|
|
|
return (&tape->rq_stack[tape->rq_stack_index++]);
|
|
|
}
|
|
|
|
|
|
-static void idetape_init_pc(struct ide_atapi_pc *pc)
|
|
|
-{
|
|
|
- memset(pc->c, 0, 12);
|
|
|
- pc->retries = 0;
|
|
|
- pc->flags = 0;
|
|
|
- pc->req_xfer = 0;
|
|
|
- pc->buf = pc->pc_buf;
|
|
|
- pc->buf_size = IDETAPE_PC_BUFFER_SIZE;
|
|
|
- pc->bh = NULL;
|
|
|
- pc->b_data = NULL;
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* called on each failed packet command retry to analyze the request sense. We
|
|
|
* currently do not utilize this information.
|
|
@@ -538,8 +523,8 @@ static void idetape_analyze_error(ide_drive_t *drive, u8 *sense)
|
|
|
if (pc->flags & PC_FLAG_DMA_ERROR) {
|
|
|
pc->xferred = pc->req_xfer -
|
|
|
tape->blk_size *
|
|
|
- be32_to_cpu(get_unaligned((u32 *)&sense[3]));
|
|
|
- idetape_update_buffers(pc);
|
|
|
+ get_unaligned_be32(&sense[3]);
|
|
|
+ idetape_update_buffers(drive, pc);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -634,21 +619,78 @@ static int idetape_end_request(ide_drive_t *drive, int uptodate, int nr_sects)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static ide_startstop_t idetape_request_sense_callback(ide_drive_t *drive)
|
|
|
+static void ide_tape_callback(ide_drive_t *drive)
|
|
|
{
|
|
|
idetape_tape_t *tape = drive->driver_data;
|
|
|
+ struct ide_atapi_pc *pc = tape->pc;
|
|
|
+ int uptodate = pc->error ? 0 : 1;
|
|
|
|
|
|
debug_log(DBG_PROCS, "Enter %s\n", __func__);
|
|
|
|
|
|
- if (!tape->pc->error) {
|
|
|
- idetape_analyze_error(drive, tape->pc->buf);
|
|
|
- idetape_end_request(drive, 1, 0);
|
|
|
- } else {
|
|
|
- printk(KERN_ERR "ide-tape: Error in REQUEST SENSE itself - "
|
|
|
- "Aborting request!\n");
|
|
|
- idetape_end_request(drive, 0, 0);
|
|
|
+ if (tape->failed_pc == pc)
|
|
|
+ tape->failed_pc = NULL;
|
|
|
+
|
|
|
+ if (pc->c[0] == REQUEST_SENSE) {
|
|
|
+ if (uptodate)
|
|
|
+ idetape_analyze_error(drive, pc->buf);
|
|
|
+ else
|
|
|
+ printk(KERN_ERR "ide-tape: Error in REQUEST SENSE "
|
|
|
+ "itself - Aborting request!\n");
|
|
|
+ } else if (pc->c[0] == READ_6 || pc->c[0] == WRITE_6) {
|
|
|
+ struct request *rq = drive->hwif->hwgroup->rq;
|
|
|
+ int blocks = pc->xferred / tape->blk_size;
|
|
|
+
|
|
|
+ tape->avg_size += blocks * tape->blk_size;
|
|
|
+
|
|
|
+ if (time_after_eq(jiffies, tape->avg_time + HZ)) {
|
|
|
+ tape->avg_speed = tape->avg_size * HZ /
|
|
|
+ (jiffies - tape->avg_time) / 1024;
|
|
|
+ tape->avg_size = 0;
|
|
|
+ tape->avg_time = jiffies;
|
|
|
+ }
|
|
|
+
|
|
|
+ tape->first_frame += blocks;
|
|
|
+ rq->current_nr_sectors -= blocks;
|
|
|
+
|
|
|
+ if (pc->error)
|
|
|
+ uptodate = pc->error;
|
|
|
+ } else if (pc->c[0] == READ_POSITION && uptodate) {
|
|
|
+ u8 *readpos = tape->pc->buf;
|
|
|
+
|
|
|
+ debug_log(DBG_SENSE, "BOP - %s\n",
|
|
|
+ (readpos[0] & 0x80) ? "Yes" : "No");
|
|
|
+ debug_log(DBG_SENSE, "EOP - %s\n",
|
|
|
+ (readpos[0] & 0x40) ? "Yes" : "No");
|
|
|
+
|
|
|
+ if (readpos[0] & 0x4) {
|
|
|
+ printk(KERN_INFO "ide-tape: Block location is unknown"
|
|
|
+ "to the tape\n");
|
|
|
+ clear_bit(IDETAPE_FLAG_ADDRESS_VALID, &tape->flags);
|
|
|
+ uptodate = 0;
|
|
|
+ } else {
|
|
|
+ debug_log(DBG_SENSE, "Block Location - %u\n",
|
|
|
+ be32_to_cpu(*(u32 *)&readpos[4]));
|
|
|
+
|
|
|
+ tape->partition = readpos[1];
|
|
|
+ tape->first_frame = be32_to_cpu(*(u32 *)&readpos[4]);
|
|
|
+ set_bit(IDETAPE_FLAG_ADDRESS_VALID, &tape->flags);
|
|
|
+ }
|
|
|
}
|
|
|
- return ide_stopped;
|
|
|
+
|
|
|
+ idetape_end_request(drive, uptodate, 0);
|
|
|
+}
|
|
|
+
|
|
|
+static void idetape_init_pc(struct ide_atapi_pc *pc)
|
|
|
+{
|
|
|
+ memset(pc->c, 0, 12);
|
|
|
+ pc->retries = 0;
|
|
|
+ pc->flags = 0;
|
|
|
+ pc->req_xfer = 0;
|
|
|
+ pc->buf = pc->pc_buf;
|
|
|
+ pc->buf_size = IDETAPE_PC_BUFFER_SIZE;
|
|
|
+ pc->bh = NULL;
|
|
|
+ pc->b_data = NULL;
|
|
|
+ pc->callback = ide_tape_callback;
|
|
|
}
|
|
|
|
|
|
static void idetape_create_request_sense_cmd(struct ide_atapi_pc *pc)
|
|
@@ -657,7 +699,6 @@ static void idetape_create_request_sense_cmd(struct ide_atapi_pc *pc)
|
|
|
pc->c[0] = REQUEST_SENSE;
|
|
|
pc->c[4] = 20;
|
|
|
pc->req_xfer = 20;
|
|
|
- pc->idetape_callback = &idetape_request_sense_callback;
|
|
|
}
|
|
|
|
|
|
static void idetape_init_rq(struct request *rq, u8 cmd)
|
|
@@ -688,9 +729,10 @@ static void idetape_queue_pc_head(ide_drive_t *drive, struct ide_atapi_pc *pc,
|
|
|
struct ide_tape_obj *tape = drive->driver_data;
|
|
|
|
|
|
idetape_init_rq(rq, REQ_IDETAPE_PC1);
|
|
|
+ rq->cmd_flags |= REQ_PREEMPT;
|
|
|
rq->buffer = (char *) pc;
|
|
|
rq->rq_disk = tape->disk;
|
|
|
- (void) ide_do_drive_cmd(drive, rq, ide_preempt);
|
|
|
+ ide_do_drive_cmd(drive, rq);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -698,7 +740,7 @@ static void idetape_queue_pc_head(ide_drive_t *drive, struct ide_atapi_pc *pc,
|
|
|
* last packet command. We queue a request sense packet command in
|
|
|
* the head of the request list.
|
|
|
*/
|
|
|
-static ide_startstop_t idetape_retry_pc (ide_drive_t *drive)
|
|
|
+static void idetape_retry_pc(ide_drive_t *drive)
|
|
|
{
|
|
|
idetape_tape_t *tape = drive->driver_data;
|
|
|
struct ide_atapi_pc *pc;
|
|
@@ -710,7 +752,6 @@ static ide_startstop_t idetape_retry_pc (ide_drive_t *drive)
|
|
|
idetape_create_request_sense_cmd(pc);
|
|
|
set_bit(IDETAPE_FLAG_IGNORE_DSC, &tape->flags);
|
|
|
idetape_queue_pc_head(drive, pc, rq);
|
|
|
- return ide_stopped;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -727,7 +768,26 @@ static void idetape_postpone_request(ide_drive_t *drive)
|
|
|
ide_stall_queue(drive, tape->dsc_poll_freq);
|
|
|
}
|
|
|
|
|
|
-typedef void idetape_io_buf(ide_drive_t *, struct ide_atapi_pc *, unsigned int);
|
|
|
+static void ide_tape_handle_dsc(ide_drive_t *drive)
|
|
|
+{
|
|
|
+ idetape_tape_t *tape = drive->driver_data;
|
|
|
+
|
|
|
+ /* Media access command */
|
|
|
+ tape->dsc_polling_start = jiffies;
|
|
|
+ tape->dsc_poll_freq = IDETAPE_DSC_MA_FAST;
|
|
|
+ tape->dsc_timeout = jiffies + IDETAPE_DSC_MA_TIMEOUT;
|
|
|
+ /* Allow ide.c to handle other requests */
|
|
|
+ idetape_postpone_request(drive);
|
|
|
+}
|
|
|
+
|
|
|
+static void ide_tape_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc,
|
|
|
+ unsigned int bcount, int write)
|
|
|
+{
|
|
|
+ if (write)
|
|
|
+ idetape_output_buffers(drive, pc, bcount);
|
|
|
+ else
|
|
|
+ idetape_input_buffers(drive, pc, bcount);
|
|
|
+}
|
|
|
|
|
|
/*
|
|
|
* This is the usual interrupt handler which will be called during a packet
|
|
@@ -738,169 +798,11 @@ typedef void idetape_io_buf(ide_drive_t *, struct ide_atapi_pc *, unsigned int);
|
|
|
*/
|
|
|
static ide_startstop_t idetape_pc_intr(ide_drive_t *drive)
|
|
|
{
|
|
|
- ide_hwif_t *hwif = drive->hwif;
|
|
|
idetape_tape_t *tape = drive->driver_data;
|
|
|
- struct ide_atapi_pc *pc = tape->pc;
|
|
|
- xfer_func_t *xferfunc;
|
|
|
- idetape_io_buf *iobuf;
|
|
|
- unsigned int temp;
|
|
|
-#if SIMULATE_ERRORS
|
|
|
- static int error_sim_count;
|
|
|
-#endif
|
|
|
- u16 bcount;
|
|
|
- u8 stat, ireason;
|
|
|
-
|
|
|
- debug_log(DBG_PROCS, "Enter %s - interrupt handler\n", __func__);
|
|
|
-
|
|
|
- /* Clear the interrupt */
|
|
|
- stat = ide_read_status(drive);
|
|
|
-
|
|
|
- if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) {
|
|
|
- if (hwif->dma_ops->dma_end(drive) || (stat & ERR_STAT)) {
|
|
|
- /*
|
|
|
- * A DMA error is sometimes expected. For example,
|
|
|
- * if the tape is crossing a filemark during a
|
|
|
- * READ command, it will issue an irq and position
|
|
|
- * itself before the filemark, so that only a partial
|
|
|
- * data transfer will occur (which causes the DMA
|
|
|
- * error). In that case, we will later ask the tape
|
|
|
- * how much bytes of the original request were
|
|
|
- * actually transferred (we can't receive that
|
|
|
- * information from the DMA engine on most chipsets).
|
|
|
- */
|
|
|
-
|
|
|
- /*
|
|
|
- * On the contrary, a DMA error is never expected;
|
|
|
- * it usually indicates a hardware error or abort.
|
|
|
- * If the tape crosses a filemark during a READ
|
|
|
- * command, it will issue an irq and position itself
|
|
|
- * after the filemark (not before). Only a partial
|
|
|
- * data transfer will occur, but no DMA error.
|
|
|
- * (AS, 19 Apr 2001)
|
|
|
- */
|
|
|
- pc->flags |= PC_FLAG_DMA_ERROR;
|
|
|
- } else {
|
|
|
- pc->xferred = pc->req_xfer;
|
|
|
- idetape_update_buffers(pc);
|
|
|
- }
|
|
|
- debug_log(DBG_PROCS, "DMA finished\n");
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- /* No more interrupts */
|
|
|
- if ((stat & DRQ_STAT) == 0) {
|
|
|
- debug_log(DBG_SENSE, "Packet command completed, %d bytes"
|
|
|
- " transferred\n", pc->xferred);
|
|
|
-
|
|
|
- pc->flags &= ~PC_FLAG_DMA_IN_PROGRESS;
|
|
|
- local_irq_enable();
|
|
|
-
|
|
|
-#if SIMULATE_ERRORS
|
|
|
- if ((pc->c[0] == WRITE_6 || pc->c[0] == READ_6) &&
|
|
|
- (++error_sim_count % 100) == 0) {
|
|
|
- printk(KERN_INFO "ide-tape: %s: simulating error\n",
|
|
|
- tape->name);
|
|
|
- stat |= ERR_STAT;
|
|
|
- }
|
|
|
-#endif
|
|
|
- if ((stat & ERR_STAT) && pc->c[0] == REQUEST_SENSE)
|
|
|
- stat &= ~ERR_STAT;
|
|
|
- if ((stat & ERR_STAT) || (pc->flags & PC_FLAG_DMA_ERROR)) {
|
|
|
- /* Error detected */
|
|
|
- debug_log(DBG_ERR, "%s: I/O error\n", tape->name);
|
|
|
-
|
|
|
- if (pc->c[0] == REQUEST_SENSE) {
|
|
|
- printk(KERN_ERR "ide-tape: I/O error in request"
|
|
|
- " sense command\n");
|
|
|
- return ide_do_reset(drive);
|
|
|
- }
|
|
|
- debug_log(DBG_ERR, "[cmd %x]: check condition\n",
|
|
|
- pc->c[0]);
|
|
|
-
|
|
|
- /* Retry operation */
|
|
|
- return idetape_retry_pc(drive);
|
|
|
- }
|
|
|
- pc->error = 0;
|
|
|
- if ((pc->flags & PC_FLAG_WAIT_FOR_DSC) &&
|
|
|
- (stat & SEEK_STAT) == 0) {
|
|
|
- /* Media access command */
|
|
|
- tape->dsc_polling_start = jiffies;
|
|
|
- tape->dsc_poll_freq = IDETAPE_DSC_MA_FAST;
|
|
|
- tape->dsc_timeout = jiffies + IDETAPE_DSC_MA_TIMEOUT;
|
|
|
- /* Allow ide.c to handle other requests */
|
|
|
- idetape_postpone_request(drive);
|
|
|
- return ide_stopped;
|
|
|
- }
|
|
|
- if (tape->failed_pc == pc)
|
|
|
- tape->failed_pc = NULL;
|
|
|
- /* Command finished - Call the callback function */
|
|
|
- return pc->idetape_callback(drive);
|
|
|
- }
|
|
|
-
|
|
|
- if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) {
|
|
|
- pc->flags &= ~PC_FLAG_DMA_IN_PROGRESS;
|
|
|
- printk(KERN_ERR "ide-tape: The tape wants to issue more "
|
|
|
- "interrupts in DMA mode\n");
|
|
|
- printk(KERN_ERR "ide-tape: DMA disabled, reverting to PIO\n");
|
|
|
- ide_dma_off(drive);
|
|
|
- return ide_do_reset(drive);
|
|
|
- }
|
|
|
- /* Get the number of bytes to transfer on this interrupt. */
|
|
|
- bcount = (hwif->INB(hwif->io_ports.lbah_addr) << 8) |
|
|
|
- hwif->INB(hwif->io_ports.lbam_addr);
|
|
|
-
|
|
|
- ireason = hwif->INB(hwif->io_ports.nsect_addr);
|
|
|
-
|
|
|
- if (ireason & CD) {
|
|
|
- printk(KERN_ERR "ide-tape: CoD != 0 in %s\n", __func__);
|
|
|
- return ide_do_reset(drive);
|
|
|
- }
|
|
|
- if (((ireason & IO) == IO) == !!(pc->flags & PC_FLAG_WRITING)) {
|
|
|
- /* Hopefully, we will never get here */
|
|
|
- printk(KERN_ERR "ide-tape: We wanted to %s, ",
|
|
|
- (ireason & IO) ? "Write" : "Read");
|
|
|
- printk(KERN_ERR "ide-tape: but the tape wants us to %s !\n",
|
|
|
- (ireason & IO) ? "Read" : "Write");
|
|
|
- return ide_do_reset(drive);
|
|
|
- }
|
|
|
- if (!(pc->flags & PC_FLAG_WRITING)) {
|
|
|
- /* Reading - Check that we have enough space */
|
|
|
- temp = pc->xferred + bcount;
|
|
|
- if (temp > pc->req_xfer) {
|
|
|
- if (temp > pc->buf_size) {
|
|
|
- printk(KERN_ERR "ide-tape: The tape wants to "
|
|
|
- "send us more data than expected "
|
|
|
- "- discarding data\n");
|
|
|
- ide_pad_transfer(drive, 0, bcount);
|
|
|
- ide_set_handler(drive, &idetape_pc_intr,
|
|
|
- IDETAPE_WAIT_CMD, NULL);
|
|
|
- return ide_started;
|
|
|
- }
|
|
|
- debug_log(DBG_SENSE, "The tape wants to send us more "
|
|
|
- "data than expected - allowing transfer\n");
|
|
|
- }
|
|
|
- iobuf = &idetape_input_buffers;
|
|
|
- xferfunc = hwif->input_data;
|
|
|
- } else {
|
|
|
- iobuf = &idetape_output_buffers;
|
|
|
- xferfunc = hwif->output_data;
|
|
|
- }
|
|
|
-
|
|
|
- if (pc->bh)
|
|
|
- iobuf(drive, pc, bcount);
|
|
|
- else
|
|
|
- xferfunc(drive, NULL, pc->cur_pos, bcount);
|
|
|
-
|
|
|
- /* Update the current position */
|
|
|
- pc->xferred += bcount;
|
|
|
- pc->cur_pos += bcount;
|
|
|
-
|
|
|
- debug_log(DBG_SENSE, "[cmd %x] transferred %d bytes on that intr.\n",
|
|
|
- pc->c[0], bcount);
|
|
|
|
|
|
- /* And set the interrupt handler again */
|
|
|
- ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
|
|
|
- return ide_started;
|
|
|
+ return ide_pc_intr(drive, tape->pc, idetape_pc_intr, IDETAPE_WAIT_CMD,
|
|
|
+ NULL, idetape_update_buffers, idetape_retry_pc,
|
|
|
+ ide_tape_handle_dsc, ide_tape_io_buffers);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -941,56 +843,16 @@ static ide_startstop_t idetape_pc_intr(ide_drive_t *drive)
|
|
|
*/
|
|
|
static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive)
|
|
|
{
|
|
|
- ide_hwif_t *hwif = drive->hwif;
|
|
|
idetape_tape_t *tape = drive->driver_data;
|
|
|
- struct ide_atapi_pc *pc = tape->pc;
|
|
|
- int retries = 100;
|
|
|
- ide_startstop_t startstop;
|
|
|
- u8 ireason;
|
|
|
-
|
|
|
- if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) {
|
|
|
- printk(KERN_ERR "ide-tape: Strange, packet command initiated "
|
|
|
- "yet DRQ isn't asserted\n");
|
|
|
- return startstop;
|
|
|
- }
|
|
|
- ireason = hwif->INB(hwif->io_ports.nsect_addr);
|
|
|
- while (retries-- && ((ireason & CD) == 0 || (ireason & IO))) {
|
|
|
- printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while issuing "
|
|
|
- "a packet command, retrying\n");
|
|
|
- udelay(100);
|
|
|
- ireason = hwif->INB(hwif->io_ports.nsect_addr);
|
|
|
- if (retries == 0) {
|
|
|
- printk(KERN_ERR "ide-tape: (IO,CoD != (0,1) while "
|
|
|
- "issuing a packet command, ignoring\n");
|
|
|
- ireason |= CD;
|
|
|
- ireason &= ~IO;
|
|
|
- }
|
|
|
- }
|
|
|
- if ((ireason & CD) == 0 || (ireason & IO)) {
|
|
|
- printk(KERN_ERR "ide-tape: (IO,CoD) != (0,1) while issuing "
|
|
|
- "a packet command\n");
|
|
|
- return ide_do_reset(drive);
|
|
|
- }
|
|
|
- /* Set the interrupt routine */
|
|
|
- ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL);
|
|
|
-#ifdef CONFIG_BLK_DEV_IDEDMA
|
|
|
- /* Begin DMA, if necessary */
|
|
|
- if (pc->flags & PC_FLAG_DMA_IN_PROGRESS)
|
|
|
- hwif->dma_ops->dma_start(drive);
|
|
|
-#endif
|
|
|
- /* Send the actual packet */
|
|
|
- hwif->output_data(drive, NULL, pc->c, 12);
|
|
|
|
|
|
- return ide_started;
|
|
|
+ return ide_transfer_pc(drive, tape->pc, idetape_pc_intr,
|
|
|
+ IDETAPE_WAIT_CMD, NULL);
|
|
|
}
|
|
|
|
|
|
static ide_startstop_t idetape_issue_pc(ide_drive_t *drive,
|
|
|
struct ide_atapi_pc *pc)
|
|
|
{
|
|
|
- ide_hwif_t *hwif = drive->hwif;
|
|
|
idetape_tape_t *tape = drive->driver_data;
|
|
|
- int dma_ok = 0;
|
|
|
- u16 bcount;
|
|
|
|
|
|
if (tape->pc->c[0] == REQUEST_SENSE &&
|
|
|
pc->c[0] == REQUEST_SENSE) {
|
|
@@ -1025,50 +887,15 @@ static ide_startstop_t idetape_issue_pc(ide_drive_t *drive,
|
|
|
pc->error = IDETAPE_ERROR_GENERAL;
|
|
|
}
|
|
|
tape->failed_pc = NULL;
|
|
|
- return pc->idetape_callback(drive);
|
|
|
+ pc->callback(drive);
|
|
|
+ return ide_stopped;
|
|
|
}
|
|
|
debug_log(DBG_SENSE, "Retry #%d, cmd = %02X\n", pc->retries, pc->c[0]);
|
|
|
|
|
|
pc->retries++;
|
|
|
- /* We haven't transferred any data yet */
|
|
|
- pc->xferred = 0;
|
|
|
- pc->cur_pos = pc->buf;
|
|
|
- /* Request to transfer the entire buffer at once */
|
|
|
- bcount = pc->req_xfer;
|
|
|
|
|
|
- if (pc->flags & PC_FLAG_DMA_ERROR) {
|
|
|
- pc->flags &= ~PC_FLAG_DMA_ERROR;
|
|
|
- printk(KERN_WARNING "ide-tape: DMA disabled, "
|
|
|
- "reverting to PIO\n");
|
|
|
- ide_dma_off(drive);
|
|
|
- }
|
|
|
- if ((pc->flags & PC_FLAG_DMA_RECOMMENDED) && drive->using_dma)
|
|
|
- dma_ok = !hwif->dma_ops->dma_setup(drive);
|
|
|
-
|
|
|
- ide_pktcmd_tf_load(drive, IDE_TFLAG_NO_SELECT_MASK |
|
|
|
- IDE_TFLAG_OUT_DEVICE, bcount, dma_ok);
|
|
|
-
|
|
|
- if (dma_ok)
|
|
|
- /* Will begin DMA later */
|
|
|
- pc->flags |= PC_FLAG_DMA_IN_PROGRESS;
|
|
|
- if (test_bit(IDETAPE_FLAG_DRQ_INTERRUPT, &tape->flags)) {
|
|
|
- ide_execute_command(drive, WIN_PACKETCMD, &idetape_transfer_pc,
|
|
|
- IDETAPE_WAIT_CMD, NULL);
|
|
|
- return ide_started;
|
|
|
- } else {
|
|
|
- ide_execute_pkt_cmd(drive);
|
|
|
- return idetape_transfer_pc(drive);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-static ide_startstop_t idetape_pc_callback(ide_drive_t *drive)
|
|
|
-{
|
|
|
- idetape_tape_t *tape = drive->driver_data;
|
|
|
-
|
|
|
- debug_log(DBG_PROCS, "Enter %s\n", __func__);
|
|
|
-
|
|
|
- idetape_end_request(drive, tape->pc->error ? 0 : 1, 0);
|
|
|
- return ide_stopped;
|
|
|
+ return ide_issue_pc(drive, pc, idetape_transfer_pc,
|
|
|
+ IDETAPE_WAIT_CMD, NULL);
|
|
|
}
|
|
|
|
|
|
/* A mode sense command is used to "sense" tape parameters. */
|
|
@@ -1096,7 +923,6 @@ static void idetape_create_mode_sense_cmd(struct ide_atapi_pc *pc, u8 page_code)
|
|
|
pc->req_xfer = 24;
|
|
|
else
|
|
|
pc->req_xfer = 50;
|
|
|
- pc->idetape_callback = &idetape_pc_callback;
|
|
|
}
|
|
|
|
|
|
static ide_startstop_t idetape_media_access_finished(ide_drive_t *drive)
|
|
@@ -1114,80 +940,41 @@ static ide_startstop_t idetape_media_access_finished(ide_drive_t *drive)
|
|
|
printk(KERN_ERR "ide-tape: %s: I/O error, ",
|
|
|
tape->name);
|
|
|
/* Retry operation */
|
|
|
- return idetape_retry_pc(drive);
|
|
|
+ idetape_retry_pc(drive);
|
|
|
+ return ide_stopped;
|
|
|
}
|
|
|
pc->error = 0;
|
|
|
- if (tape->failed_pc == pc)
|
|
|
- tape->failed_pc = NULL;
|
|
|
} else {
|
|
|
pc->error = IDETAPE_ERROR_GENERAL;
|
|
|
tape->failed_pc = NULL;
|
|
|
}
|
|
|
- return pc->idetape_callback(drive);
|
|
|
-}
|
|
|
-
|
|
|
-static ide_startstop_t idetape_rw_callback(ide_drive_t *drive)
|
|
|
-{
|
|
|
- idetape_tape_t *tape = drive->driver_data;
|
|
|
- struct request *rq = HWGROUP(drive)->rq;
|
|
|
- int blocks = tape->pc->xferred / tape->blk_size;
|
|
|
-
|
|
|
- tape->avg_size += blocks * tape->blk_size;
|
|
|
-
|
|
|
- if (time_after_eq(jiffies, tape->avg_time + HZ)) {
|
|
|
- tape->avg_speed = tape->avg_size * HZ /
|
|
|
- (jiffies - tape->avg_time) / 1024;
|
|
|
- tape->avg_size = 0;
|
|
|
- tape->avg_time = jiffies;
|
|
|
- }
|
|
|
- debug_log(DBG_PROCS, "Enter %s\n", __func__);
|
|
|
-
|
|
|
- tape->first_frame += blocks;
|
|
|
- rq->current_nr_sectors -= blocks;
|
|
|
-
|
|
|
- if (!tape->pc->error)
|
|
|
- idetape_end_request(drive, 1, 0);
|
|
|
- else
|
|
|
- idetape_end_request(drive, tape->pc->error, 0);
|
|
|
+ pc->callback(drive);
|
|
|
return ide_stopped;
|
|
|
}
|
|
|
|
|
|
-static void idetape_create_read_cmd(idetape_tape_t *tape,
|
|
|
- struct ide_atapi_pc *pc,
|
|
|
- unsigned int length, struct idetape_bh *bh)
|
|
|
+static void ide_tape_create_rw_cmd(idetape_tape_t *tape,
|
|
|
+ struct ide_atapi_pc *pc, unsigned int length,
|
|
|
+ struct idetape_bh *bh, u8 opcode)
|
|
|
{
|
|
|
idetape_init_pc(pc);
|
|
|
- pc->c[0] = READ_6;
|
|
|
put_unaligned(cpu_to_be32(length), (unsigned int *) &pc->c[1]);
|
|
|
pc->c[1] = 1;
|
|
|
- pc->idetape_callback = &idetape_rw_callback;
|
|
|
pc->bh = bh;
|
|
|
- atomic_set(&bh->b_count, 0);
|
|
|
pc->buf = NULL;
|
|
|
pc->buf_size = length * tape->blk_size;
|
|
|
pc->req_xfer = pc->buf_size;
|
|
|
if (pc->req_xfer == tape->buffer_size)
|
|
|
- pc->flags |= PC_FLAG_DMA_RECOMMENDED;
|
|
|
-}
|
|
|
+ pc->flags |= PC_FLAG_DMA_OK;
|
|
|
|
|
|
-static void idetape_create_write_cmd(idetape_tape_t *tape,
|
|
|
- struct ide_atapi_pc *pc,
|
|
|
- unsigned int length, struct idetape_bh *bh)
|
|
|
-{
|
|
|
- idetape_init_pc(pc);
|
|
|
- pc->c[0] = WRITE_6;
|
|
|
- put_unaligned(cpu_to_be32(length), (unsigned int *) &pc->c[1]);
|
|
|
- pc->c[1] = 1;
|
|
|
- pc->idetape_callback = &idetape_rw_callback;
|
|
|
- pc->flags |= PC_FLAG_WRITING;
|
|
|
- pc->bh = bh;
|
|
|
- pc->b_data = bh->b_data;
|
|
|
- pc->b_count = atomic_read(&bh->b_count);
|
|
|
- pc->buf = NULL;
|
|
|
- pc->buf_size = length * tape->blk_size;
|
|
|
- pc->req_xfer = pc->buf_size;
|
|
|
- if (pc->req_xfer == tape->buffer_size)
|
|
|
- pc->flags |= PC_FLAG_DMA_RECOMMENDED;
|
|
|
+ if (opcode == READ_6) {
|
|
|
+ pc->c[0] = READ_6;
|
|
|
+ atomic_set(&bh->b_count, 0);
|
|
|
+ } else if (opcode == WRITE_6) {
|
|
|
+ pc->c[0] = WRITE_6;
|
|
|
+ pc->flags |= PC_FLAG_WRITING;
|
|
|
+ pc->b_data = bh->b_data;
|
|
|
+ pc->b_count = atomic_read(&bh->b_count);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static ide_startstop_t idetape_do_request(ide_drive_t *drive,
|
|
@@ -1211,8 +998,10 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
|
|
|
}
|
|
|
|
|
|
/* Retry a failed packet command */
|
|
|
- if (tape->failed_pc && tape->pc->c[0] == REQUEST_SENSE)
|
|
|
- return idetape_issue_pc(drive, tape->failed_pc);
|
|
|
+ if (tape->failed_pc && tape->pc->c[0] == REQUEST_SENSE) {
|
|
|
+ pc = tape->failed_pc;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
|
|
|
if (postponed_rq != NULL)
|
|
|
if (rq != postponed_rq) {
|
|
@@ -1262,14 +1051,16 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
|
|
|
}
|
|
|
if (rq->cmd[0] & REQ_IDETAPE_READ) {
|
|
|
pc = idetape_next_pc_storage(drive);
|
|
|
- idetape_create_read_cmd(tape, pc, rq->current_nr_sectors,
|
|
|
- (struct idetape_bh *)rq->special);
|
|
|
+ ide_tape_create_rw_cmd(tape, pc, rq->current_nr_sectors,
|
|
|
+ (struct idetape_bh *)rq->special,
|
|
|
+ READ_6);
|
|
|
goto out;
|
|
|
}
|
|
|
if (rq->cmd[0] & REQ_IDETAPE_WRITE) {
|
|
|
pc = idetape_next_pc_storage(drive);
|
|
|
- idetape_create_write_cmd(tape, pc, rq->current_nr_sectors,
|
|
|
- (struct idetape_bh *)rq->special);
|
|
|
+ ide_tape_create_rw_cmd(tape, pc, rq->current_nr_sectors,
|
|
|
+ (struct idetape_bh *)rq->special,
|
|
|
+ WRITE_6);
|
|
|
goto out;
|
|
|
}
|
|
|
if (rq->cmd[0] & REQ_IDETAPE_PC1) {
|
|
@@ -1284,6 +1075,9 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
|
|
|
}
|
|
|
BUG();
|
|
|
out:
|
|
|
+ if (test_bit(IDETAPE_FLAG_DRQ_INTERRUPT, &tape->flags))
|
|
|
+ pc->flags |= PC_FLAG_DRQ_INTERRUPT;
|
|
|
+
|
|
|
return idetape_issue_pc(drive, pc);
|
|
|
}
|
|
|
|
|
@@ -1447,40 +1241,6 @@ static void idetape_init_merge_buffer(idetape_tape_t *tape)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static ide_startstop_t idetape_read_position_callback(ide_drive_t *drive)
|
|
|
-{
|
|
|
- idetape_tape_t *tape = drive->driver_data;
|
|
|
- u8 *readpos = tape->pc->buf;
|
|
|
-
|
|
|
- debug_log(DBG_PROCS, "Enter %s\n", __func__);
|
|
|
-
|
|
|
- if (!tape->pc->error) {
|
|
|
- debug_log(DBG_SENSE, "BOP - %s\n",
|
|
|
- (readpos[0] & 0x80) ? "Yes" : "No");
|
|
|
- debug_log(DBG_SENSE, "EOP - %s\n",
|
|
|
- (readpos[0] & 0x40) ? "Yes" : "No");
|
|
|
-
|
|
|
- if (readpos[0] & 0x4) {
|
|
|
- printk(KERN_INFO "ide-tape: Block location is unknown"
|
|
|
- "to the tape\n");
|
|
|
- clear_bit(IDETAPE_FLAG_ADDRESS_VALID, &tape->flags);
|
|
|
- idetape_end_request(drive, 0, 0);
|
|
|
- } else {
|
|
|
- debug_log(DBG_SENSE, "Block Location - %u\n",
|
|
|
- be32_to_cpu(*(u32 *)&readpos[4]));
|
|
|
-
|
|
|
- tape->partition = readpos[1];
|
|
|
- tape->first_frame =
|
|
|
- be32_to_cpu(*(u32 *)&readpos[4]);
|
|
|
- set_bit(IDETAPE_FLAG_ADDRESS_VALID, &tape->flags);
|
|
|
- idetape_end_request(drive, 1, 0);
|
|
|
- }
|
|
|
- } else {
|
|
|
- idetape_end_request(drive, 0, 0);
|
|
|
- }
|
|
|
- return ide_stopped;
|
|
|
-}
|
|
|
-
|
|
|
/*
|
|
|
* Write a filemark if write_filemark=1. Flush the device buffers without
|
|
|
* writing a filemark otherwise.
|
|
@@ -1492,14 +1252,12 @@ static void idetape_create_write_filemark_cmd(ide_drive_t *drive,
|
|
|
pc->c[0] = WRITE_FILEMARKS;
|
|
|
pc->c[4] = write_filemark;
|
|
|
pc->flags |= PC_FLAG_WAIT_FOR_DSC;
|
|
|
- pc->idetape_callback = &idetape_pc_callback;
|
|
|
}
|
|
|
|
|
|
static void idetape_create_test_unit_ready_cmd(struct ide_atapi_pc *pc)
|
|
|
{
|
|
|
idetape_init_pc(pc);
|
|
|
pc->c[0] = TEST_UNIT_READY;
|
|
|
- pc->idetape_callback = &idetape_pc_callback;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -1518,12 +1276,16 @@ static void idetape_create_test_unit_ready_cmd(struct ide_atapi_pc *pc)
|
|
|
static int idetape_queue_pc_tail(ide_drive_t *drive, struct ide_atapi_pc *pc)
|
|
|
{
|
|
|
struct ide_tape_obj *tape = drive->driver_data;
|
|
|
- struct request rq;
|
|
|
+ struct request *rq;
|
|
|
+ int error;
|
|
|
|
|
|
- idetape_init_rq(&rq, REQ_IDETAPE_PC1);
|
|
|
- rq.buffer = (char *) pc;
|
|
|
- rq.rq_disk = tape->disk;
|
|
|
- return ide_do_drive_cmd(drive, &rq, ide_wait);
|
|
|
+ rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
|
|
|
+ rq->cmd_type = REQ_TYPE_SPECIAL;
|
|
|
+ rq->cmd[0] = REQ_IDETAPE_PC1;
|
|
|
+ rq->buffer = (char *)pc;
|
|
|
+ error = blk_execute_rq(drive->queue, tape->disk, rq, 0);
|
|
|
+ blk_put_request(rq);
|
|
|
+ return error;
|
|
|
}
|
|
|
|
|
|
static void idetape_create_load_unload_cmd(ide_drive_t *drive,
|
|
@@ -1533,7 +1295,6 @@ static void idetape_create_load_unload_cmd(ide_drive_t *drive,
|
|
|
pc->c[0] = START_STOP;
|
|
|
pc->c[4] = cmd;
|
|
|
pc->flags |= PC_FLAG_WAIT_FOR_DSC;
|
|
|
- pc->idetape_callback = &idetape_pc_callback;
|
|
|
}
|
|
|
|
|
|
static int idetape_wait_ready(ide_drive_t *drive, unsigned long timeout)
|
|
@@ -1585,7 +1346,6 @@ static void idetape_create_read_position_cmd(struct ide_atapi_pc *pc)
|
|
|
idetape_init_pc(pc);
|
|
|
pc->c[0] = READ_POSITION;
|
|
|
pc->req_xfer = 20;
|
|
|
- pc->idetape_callback = &idetape_read_position_callback;
|
|
|
}
|
|
|
|
|
|
static int idetape_read_position(ide_drive_t *drive)
|
|
@@ -1613,7 +1373,6 @@ static void idetape_create_locate_cmd(ide_drive_t *drive,
|
|
|
put_unaligned(cpu_to_be32(block), (unsigned int *) &pc->c[3]);
|
|
|
pc->c[8] = partition;
|
|
|
pc->flags |= PC_FLAG_WAIT_FOR_DSC;
|
|
|
- pc->idetape_callback = &idetape_pc_callback;
|
|
|
}
|
|
|
|
|
|
static int idetape_create_prevent_cmd(ide_drive_t *drive,
|
|
@@ -1628,7 +1387,6 @@ static int idetape_create_prevent_cmd(ide_drive_t *drive,
|
|
|
idetape_init_pc(pc);
|
|
|
pc->c[0] = ALLOW_MEDIUM_REMOVAL;
|
|
|
pc->c[4] = prevent;
|
|
|
- pc->idetape_callback = &idetape_pc_callback;
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
@@ -1700,26 +1458,33 @@ static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int blocks,
|
|
|
struct idetape_bh *bh)
|
|
|
{
|
|
|
idetape_tape_t *tape = drive->driver_data;
|
|
|
- struct request rq;
|
|
|
+ struct request *rq;
|
|
|
+ int ret, errors;
|
|
|
|
|
|
debug_log(DBG_SENSE, "%s: cmd=%d\n", __func__, cmd);
|
|
|
|
|
|
- idetape_init_rq(&rq, cmd);
|
|
|
- rq.rq_disk = tape->disk;
|
|
|
- rq.special = (void *)bh;
|
|
|
- rq.sector = tape->first_frame;
|
|
|
- rq.nr_sectors = blocks;
|
|
|
- rq.current_nr_sectors = blocks;
|
|
|
- (void) ide_do_drive_cmd(drive, &rq, ide_wait);
|
|
|
+ rq = blk_get_request(drive->queue, READ, __GFP_WAIT);
|
|
|
+ rq->cmd_type = REQ_TYPE_SPECIAL;
|
|
|
+ rq->cmd[0] = cmd;
|
|
|
+ rq->rq_disk = tape->disk;
|
|
|
+ rq->special = (void *)bh;
|
|
|
+ rq->sector = tape->first_frame;
|
|
|
+ rq->nr_sectors = blocks;
|
|
|
+ rq->current_nr_sectors = blocks;
|
|
|
+ blk_execute_rq(drive->queue, tape->disk, rq, 0);
|
|
|
+
|
|
|
+ errors = rq->errors;
|
|
|
+ ret = tape->blk_size * (blocks - rq->current_nr_sectors);
|
|
|
+ blk_put_request(rq);
|
|
|
|
|
|
if ((cmd & (REQ_IDETAPE_READ | REQ_IDETAPE_WRITE)) == 0)
|
|
|
return 0;
|
|
|
|
|
|
if (tape->merge_bh)
|
|
|
idetape_init_merge_buffer(tape);
|
|
|
- if (rq.errors == IDETAPE_ERROR_GENERAL)
|
|
|
+ if (errors == IDETAPE_ERROR_GENERAL)
|
|
|
return -EIO;
|
|
|
- return (tape->blk_size * (blocks-rq.current_nr_sectors));
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
static void idetape_create_inquiry_cmd(struct ide_atapi_pc *pc)
|
|
@@ -1728,7 +1493,6 @@ static void idetape_create_inquiry_cmd(struct ide_atapi_pc *pc)
|
|
|
pc->c[0] = INQUIRY;
|
|
|
pc->c[4] = 254;
|
|
|
pc->req_xfer = 254;
|
|
|
- pc->idetape_callback = &idetape_pc_callback;
|
|
|
}
|
|
|
|
|
|
static void idetape_create_rewind_cmd(ide_drive_t *drive,
|
|
@@ -1737,7 +1501,6 @@ static void idetape_create_rewind_cmd(ide_drive_t *drive,
|
|
|
idetape_init_pc(pc);
|
|
|
pc->c[0] = REZERO_UNIT;
|
|
|
pc->flags |= PC_FLAG_WAIT_FOR_DSC;
|
|
|
- pc->idetape_callback = &idetape_pc_callback;
|
|
|
}
|
|
|
|
|
|
static void idetape_create_erase_cmd(struct ide_atapi_pc *pc)
|
|
@@ -1746,7 +1509,6 @@ static void idetape_create_erase_cmd(struct ide_atapi_pc *pc)
|
|
|
pc->c[0] = ERASE;
|
|
|
pc->c[1] = 1;
|
|
|
pc->flags |= PC_FLAG_WAIT_FOR_DSC;
|
|
|
- pc->idetape_callback = &idetape_pc_callback;
|
|
|
}
|
|
|
|
|
|
static void idetape_create_space_cmd(struct ide_atapi_pc *pc, int count, u8 cmd)
|
|
@@ -1756,7 +1518,6 @@ static void idetape_create_space_cmd(struct ide_atapi_pc *pc, int count, u8 cmd)
|
|
|
put_unaligned(cpu_to_be32(count), (unsigned int *) &pc->c[1]);
|
|
|
pc->c[1] = cmd;
|
|
|
pc->flags |= PC_FLAG_WAIT_FOR_DSC;
|
|
|
- pc->idetape_callback = &idetape_pc_callback;
|
|
|
}
|
|
|
|
|
|
/* Queue up a character device originated write request. */
|
|
@@ -2751,9 +2512,8 @@ static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor)
|
|
|
* Ensure that the number we got makes sense; limit it within
|
|
|
* IDETAPE_DSC_RW_MIN and IDETAPE_DSC_RW_MAX.
|
|
|
*/
|
|
|
- tape->best_dsc_rw_freq = max_t(unsigned long,
|
|
|
- min_t(unsigned long, t, IDETAPE_DSC_RW_MAX),
|
|
|
- IDETAPE_DSC_RW_MIN);
|
|
|
+ tape->best_dsc_rw_freq = clamp_t(unsigned long, t, IDETAPE_DSC_RW_MIN,
|
|
|
+ IDETAPE_DSC_RW_MAX);
|
|
|
printk(KERN_INFO "ide-tape: %s <-> %s: %dKBps, %d*%dkB buffer, "
|
|
|
"%lums tDSC%s\n",
|
|
|
drive->name, tape->name, *(u16 *)&tape->caps[14],
|
|
@@ -2905,11 +2665,6 @@ static int ide_tape_probe(ide_drive_t *drive)
|
|
|
" the driver\n", drive->name);
|
|
|
goto failed;
|
|
|
}
|
|
|
- if (drive->scsi) {
|
|
|
- printk(KERN_INFO "ide-tape: passing drive %s to ide-scsi"
|
|
|
- " emulation.\n", drive->name);
|
|
|
- goto failed;
|
|
|
- }
|
|
|
tape = kzalloc(sizeof(idetape_tape_t), GFP_KERNEL);
|
|
|
if (tape == NULL) {
|
|
|
printk(KERN_ERR "ide-tape: %s: Can't allocate a tape struct\n",
|