Commit a25d5826 authored by Alan Cox's avatar Alan Cox Committed by Linus Torvalds

[PATCH] update the qic02 tape driver to 2.5.44

parent 693bef4c
...@@ -116,26 +116,28 @@ ...@@ -116,26 +116,28 @@
* card+drive info if runtime configuration has been selected. * card+drive info if runtime configuration has been selected.
*/ */
static struct mtconfiginfo qic02_tape_dynconf = /* user settable */ static struct mtconfiginfo qic02_tape_dynconf = {
{ 0, 0, BOGUS_IRQ, 0, 0, TPQD_DEFAULT_FLAGS, }; /* user settable */
0, 0, BOGUS_IRQ, 0, 0, TPQD_DEFAULT_FLAGS,
};
static struct qic02_ccb qic02_tape_ccb; /* private stuff */ static struct qic02_ccb qic02_tape_ccb; /* private stuff */
#else #else
unsigned long qic02_tape_debug = TPQD_DEFAULT_FLAGS; static unsigned long qic02_tape_debug = TPQD_DEFAULT_FLAGS;
# if ((QIC02_TAPE_IFC!=WANGTEK) && (QIC02_TAPE_IFC!=ARCHIVE) && (QIC02_TAPE_IFC!=MOUNTAIN)) # if ((QIC02_TAPE_IFC!=WANGTEK) && (QIC02_TAPE_IFC!=ARCHIVE) && (QIC02_TAPE_IFC!=MOUNTAIN))
# error No valid interface card specified # error No valid interface card specified
# endif # endif
#endif /* CONFIG_QIC02_DYNCONF */ #endif /* CONFIG_QIC02_DYNCONF */
static volatile int ctlbits; /* control reg bits for tape interface */ static int ctlbits; /* control reg bits for tape interface */
static wait_queue_head_t qic02_tape_transfer; /* sync rw with interrupts */ static wait_queue_head_t qic02_tape_transfer; /* sync rw with interrupts */
static volatile struct mtget ioctl_status; /* current generic status */ static struct mtget ioctl_status; /* current generic status */
static volatile struct tpstatus tperror; /* last drive status */ static struct tpstatus tperror; /* last drive status */
static char rcs_revision[] = "$Revision: 1.10 $"; static char rcs_revision[] = "$Revision: 1.10 $";
static char rcs_date[] = "$Date: 1997/01/26 07:13:20 $"; static char rcs_date[] = "$Date: 1997/01/26 07:13:20 $";
...@@ -145,32 +147,34 @@ static char rcs_date[] = "$Date: 1997/01/26 07:13:20 $"; ...@@ -145,32 +147,34 @@ static char rcs_date[] = "$Date: 1997/01/26 07:13:20 $";
* Some variables need `volatile' because they may be modified * Some variables need `volatile' because they may be modified
* by an interrupt. * by an interrupt.
*/ */
static volatile flag status_dead = YES; /* device is legally dead until proven alive */ static flag status_dead = YES; /* device is legally dead until proven alive */
static flag status_zombie = YES; /* it's `zombie' until irq/dma allocated */ static flag status_zombie = YES; /* it's `zombie' until irq/dma allocated */
static volatile flag status_bytes_wr = NO; /* write FM at close or not */ static flag status_bytes_wr = NO; /* write FM at close or not */
static volatile flag status_bytes_rd = NO; /* (rd|wr) used for rewinding */ static flag status_bytes_rd = NO; /* (rd|wr) used for rewinding */
static volatile unsigned long status_cmd_pending; /* cmd in progress */ static volatile unsigned long status_cmd_pending; /* cmd in progress */
static volatile flag status_expect_int = NO; /* ready for interrupts */ static flag status_expect_int = NO; /* ready for interrupts */
static volatile flag status_timer_on = NO; /* using time-out */ static flag status_timer_on = NO; /* using time-out */
static volatile int status_error; /* int handler may detect error */ static int status_error; /* int handler may detect error */
static volatile flag status_eof_detected = NO; /* end of file */ static flag status_eof_detected = NO; /* end of file */
static volatile flag status_eom_detected = NO; /* end of recorded media */ static flag status_eom_detected = NO; /* end of recorded media */
static volatile flag status_eot_detected = NO; /* end of tape */ static flag status_eot_detected = NO; /* end of tape */
static volatile flag doing_read = NO; static flag doing_read = NO;
static volatile flag doing_write = NO; static flag doing_write = NO;
static volatile unsigned long dma_bytes_todo; static unsigned long dma_bytes_todo;
static volatile unsigned long dma_bytes_done; static unsigned long dma_bytes_done;
static volatile unsigned dma_mode; /* !=0 also means DMA in use */ static volatile unsigned dma_mode; /* !=0 also means DMA in use */
static flag need_rewind = YES; static flag need_rewind = YES;
static kdev_t current_tape_dev; static kdev_t current_tape_dev;
static int extra_blocks_left = BLOCKS_BEYOND_EW; static int extra_blocks_left = BLOCKS_BEYOND_EW;
static struct timer_list tp_timer; static struct timer_list tp_timer;
static unsigned long tape_open; /* Guard open one only */
static DECLARE_MUTEX(tape_op); /* Serialize tape operations */
/* return_*_eof: /* return_*_eof:
* NO: not at EOF, * NO: not at EOF,
* YES: tell app EOF was reached (return 0). * YES: tell app EOF was reached (return 0).
...@@ -183,6 +187,7 @@ static struct timer_list tp_timer; ...@@ -183,6 +187,7 @@ static struct timer_list tp_timer;
* move on to the next file. * move on to the next file.
* *
*/ */
static flag return_read_eof = NO; /* set to signal app EOF was reached */ static flag return_read_eof = NO; /* set to signal app EOF was reached */
static flag return_write_eof = NO; static flag return_write_eof = NO;
static flag reported_read_eof = NO; /* set when we've done that */ static flag reported_read_eof = NO; /* set when we've done that */
...@@ -248,70 +253,34 @@ static struct exception_list_type { ...@@ -248,70 +253,34 @@ static struct exception_list_type {
const char *msg; const char *msg;
/* EXC_nr attribute should match with tpqic02.h */ /* EXC_nr attribute should match with tpqic02.h */
} exception_list[] = { } exception_list[] = {
{ { 0, 0, "Unknown exception status code", /* extra: 0 */ },
0, 0, "Unknown exception status code", /* extra: 0 */ }, { ~(0), TP_ST0 | TP_CNI | TP_USL | TP_WRP, "Drive not online" /* 1 */ }, /* Drive presence goes before cartridge presence. */
{ { ~(TP_WRP | TP_USL), TP_ST0 | TP_CNI,
~(0), TP_ST0 | TP_CNI | TP_USL | TP_WRP,
"Drive not online" /* 1 */ },
/* Drive presence goes before cartridge presence. */
{
~(TP_WRP | TP_USL), TP_ST0 | TP_CNI,
/* My Wangtek 5150EQ sometimes reports a status code /* My Wangtek 5150EQ sometimes reports a status code
* of 0x00e0, which is not a valid exception code, but * of 0x00e0, which is not a valid exception code, but
* I think it should be recognized as "NO CARTRIDGE". * I think it should be recognized as "NO CARTRIDGE".
*/ */
"Cartridge not in place" /* 2 */ }, "Cartridge not in place" /* 2 */ },
{ { (unsigned short) ~(TP_ST1 | TP_BOM), (TP_ST0 | TP_WRP), "Write protected cartridge" /* 3 */ },
(unsigned short) ~(TP_ST1 | TP_BOM), (TP_ST0 | TP_WRP), { (unsigned short) ~(TP_ST1 | TP_EOR), (TP_ST0 | TP_EOM), "End of media" /* 4 */ },
"Write protected cartridge" /* 3 */ }, { ~TP_WRP, TP_ST0 | TP_UDA | TP_ST1 | TP_BOM, "Read or Write abort. Rewind tape." /* 5 */ },
{ { ~TP_WRP, TP_ST0 | TP_UDA, "Read error. Bad block transferred." /* 6 */ },
(unsigned short) ~(TP_ST1 | TP_EOR), (TP_ST0 | TP_EOM), { ~TP_WRP, TP_ST0 | TP_UDA | TP_BNL, "Read error. Filler block transferred." /* 7 */ },
"End of media" /* 4 */ }, { ~TP_WRP, TP_ST0 | TP_UDA | TP_BNL | TP_ST1 | TP_NDT, "Read error. No data detected." /* 8 */ },
{ { ~TP_WRP, TP_ST0 | TP_EOM | TP_UDA | TP_BNL | TP_ST1 | TP_NDT, "Read error. No data detected. EOM." /* 9 */ },
~TP_WRP, TP_ST0 | TP_UDA | TP_ST1 | TP_BOM, { ~(TP_WRP | TP_MBD | TP_PAR | TP_EOR), TP_ST0 | TP_UDA | TP_BNL | TP_ST1 | TP_NDT | TP_BOM, "Read error. No data detected. BOM." /* 10 */ },
"Read or Write abort. Rewind tape." /* 5 */ }, { ~(TP_WRP | TP_EOM), TP_ST0 | TP_FIL,
{
~TP_WRP, TP_ST0 | TP_UDA,
"Read error. Bad block transferred." /* 6 */ },
{
~TP_WRP, TP_ST0 | TP_UDA | TP_BNL,
"Read error. Filler block transferred." /* 7 */ },
{
~TP_WRP, TP_ST0 | TP_UDA | TP_BNL | TP_ST1 | TP_NDT,
"Read error. No data detected." /* 8 */ },
{
~TP_WRP,
TP_ST0 | TP_EOM | TP_UDA | TP_BNL | TP_ST1 |
TP_NDT, "Read error. No data detected. EOM." /* 9 */ },
{
~(TP_WRP | TP_MBD | TP_PAR | TP_EOR),
TP_ST0 | TP_UDA | TP_BNL | TP_ST1 | TP_NDT |
TP_BOM,
"Read error. No data detected. BOM." /* 10 */ },
{
~(TP_WRP | TP_EOM), TP_ST0 | TP_FIL,
/* Status 0x0089 (EOM & FM) is viewed as an FM, /* Status 0x0089 (EOM & FM) is viewed as an FM,
* because it can only happen during a read. * because it can only happen during a read.
* EOM is checked separately for an FM condition. * EOM is checked separately for an FM condition.
*/ */
"File mark detected" /* 11 */ }, "File mark detected" /* 11 */ },
{ { ~(TP_ST0 | TP_CNI | TP_USL | TP_WRP | TP_BOM), TP_ST1 | TP_ILL, "Illegal command" /* 12 */ },
~(TP_ST0 | TP_CNI | TP_USL | TP_WRP | TP_BOM), { ~(TP_ST0 | TP_CNI | TP_USL | TP_WRP | TP_BOM), TP_ST1 | TP_POR, "Reset occurred" /* 13 */ },
TP_ST1 | TP_ILL, "Illegal command" /* 12 */ }, { ~TP_WRP, TP_ST0 | TP_FIL | TP_MBD, /* NOTE: ST1 not set! */ "Marginal block detected" /* 14 */ },
{ { ~(TP_ST0 | TP_WRP | TP_EOM | TP_UDA | TP_BNL | TP_FIL | TP_NDT), TP_ST1 | TP_EOR, /********** Is the extra TP_NDT really needed Eddy? **********/ "End of recorded media" /* extra: 15 */ },
~(TP_ST0 | TP_CNI | TP_USL | TP_WRP | TP_BOM),
TP_ST1 | TP_POR, "Reset occurred" /* 13 */ },
{
~TP_WRP, TP_ST0 | TP_FIL | TP_MBD, /* NOTE: ST1 not set! */
"Marginal block detected" /* 14 */ },
{
~(TP_ST0 | TP_WRP | TP_EOM | TP_UDA | TP_BNL | TP_FIL |
TP_NDT), TP_ST1 | TP_EOR,
/********** Is the extra TP_NDT really needed Eddy? **********/
"End of recorded media" /* extra: 15 */ },
/* 15 is returned when SEEKEOD completes successfully */ /* 15 is returned when SEEKEOD completes successfully */
{ { ~(TP_WRP | TP_ST0), TP_ST1 | TP_BOM, "Beginning of media" /* extra: 16 */ }
~(TP_WRP | TP_ST0), TP_ST1 | TP_BOM, "Beginning of media" /* extra: 16 */ }
}; };
#define NR_OF_EXC (sizeof(exception_list)/sizeof(struct exception_list_type)) #define NR_OF_EXC (sizeof(exception_list)/sizeof(struct exception_list_type))
...@@ -333,24 +302,12 @@ static void tpqputs(unsigned long flags, const char *s) ...@@ -333,24 +302,12 @@ static void tpqputs(unsigned long flags, const char *s)
} /* tpqputs */ } /* tpqputs */
/* Perform byte order swapping for a 16-bit word.
*
* [FIXME] This should probably be in include/asm/
* ([FIXME] i486 can do this faster)
*/
static inline void byte_swap_w(volatile unsigned short *w)
{
int t = *w;
*w = (t >> 8) | ((t & 0xff) << 8);
}
/* Init control register bits on interface card. /* Init control register bits on interface card.
* For Archive, interrupts must be enabled explicitly. * For Archive, interrupts must be enabled explicitly.
* Wangtek interface card requires ONLINE to be set, Archive SC402/SC499R * Wangtek interface card requires ONLINE to be set, Archive SC402/SC499R
* cards keep it active all the time. * cards keep it active all the time.
*/ */
static void ifc_init(void) static void ifc_init(void)
{ {
if (QIC02_TAPE_IFC == WANGTEK) { /* || (QIC02_TAPE_IFC == EVEREX) */ if (QIC02_TAPE_IFC == WANGTEK) { /* || (QIC02_TAPE_IFC == EVEREX) */
...@@ -374,10 +331,8 @@ static void report_qic_exception(unsigned n) ...@@ -374,10 +331,8 @@ static void report_qic_exception(unsigned n)
tpqputs(TPQD_ALWAYS, "Oops -- report_qic_exception"); tpqputs(TPQD_ALWAYS, "Oops -- report_qic_exception");
n = 0; n = 0;
} }
if (TPQDBG(SENSE_TEXT) || n == 0) { if (TPQDBG(SENSE_TEXT) || n == 0)
printk(TPQIC02_NAME ": sense: %s\n", printk(TPQIC02_NAME ": sense: %s\n", exception_list[n].msg);
exception_list[n].msg);
}
} /* report_qic_exception */ } /* report_qic_exception */
...@@ -395,9 +350,7 @@ static int decode_qic_exception_nr(unsigned s) ...@@ -395,9 +350,7 @@ static int decode_qic_exception_nr(unsigned s)
return i; return i;
} }
} }
printk(TPQIC02_NAME printk(TPQIC02_NAME ": decode_qic_exception_nr: exception(%x) not recognized\n", s);
": decode_qic_exception_nr: exception(%x) not recognized\n",
s);
return 0; return 0;
} /* decode_qic_exception_nr */ } /* decode_qic_exception_nr */
...@@ -477,15 +430,13 @@ static int tape_reset(int verbose) ...@@ -477,15 +430,13 @@ static int tape_reset(int verbose)
/* KLUDGE FOR G++ BUG */ /* KLUDGE FOR G++ BUG */
{ {
int stat = inb_p(QIC02_STAT_PORT); int stat = inb_p(QIC02_STAT_PORT);
status_dead = status_dead = ((stat & QIC02_STAT_RESETMASK) != QIC02_STAT_RESETVAL);
((stat & QIC02_STAT_RESETMASK) != QIC02_STAT_RESETVAL);
} }
/* if successful, inb(STAT) returned RESETVAL */ /* if successful, inb(STAT) returned RESETVAL */
if (status_dead == YES) { if (status_dead == YES)
printk(TPQIC02_NAME ": reset failed!\n"); printk(TPQIC02_NAME ": reset failed!\n");
} else if (verbose) { else if (verbose)
printk(TPQIC02_NAME ": reset successful\n"); printk(TPQIC02_NAME ": reset successful\n");
}
return (status_dead == YES) ? TE_DEAD : TE_OK; return (status_dead == YES) ? TE_DEAD : TE_OK;
} /* tape_reset */ } /* tape_reset */
...@@ -528,11 +479,10 @@ static int notify_cmd(char cmd, short ignore_ex) ...@@ -528,11 +479,10 @@ static int notify_cmd(char cmd, short ignore_ex)
* it could be *much* longer! * it could be *much* longer!
*/ */
while ((inb_p(QIC02_STAT_PORT) & QIC02_STAT_READY) && (--i > 0)) while ((inb_p(QIC02_STAT_PORT) & QIC02_STAT_READY) && (--i > 0))
/*skip */ ; udelay(1);
/* wait for ready */ /* wait for ready */
if (i == 0) { if (i == 0) {
tpqputs(TPQD_ALWAYS, tpqputs(TPQD_ALWAYS, "timed out waiting for ready in notify_cmd");
"timed out waiting for ready in notify_cmd");
status_dead = YES; status_dead = YES;
return TE_TIM; return TE_TIM;
} }
...@@ -541,7 +491,7 @@ static int notify_cmd(char cmd, short ignore_ex) ...@@ -541,7 +491,7 @@ static int notify_cmd(char cmd, short ignore_ex)
i = TAPE_NOTIFY_TIMEOUT; i = TAPE_NOTIFY_TIMEOUT;
/* according to the specs this one should never time-out */ /* according to the specs this one should never time-out */
while (((inb_p(QIC02_STAT_PORT) & QIC02_STAT_READY) == 0) && (--i > 0)) while (((inb_p(QIC02_STAT_PORT) & QIC02_STAT_READY) == 0) && (--i > 0))
/*skip */ ; udelay(1);
/* wait for not ready */ /* wait for not ready */
if (i == 0) { if (i == 0) {
tpqputs(TPQD_ALWAYS, "timed out waiting for !ready in notify_cmd"); tpqputs(TPQD_ALWAYS, "timed out waiting for !ready in notify_cmd");
...@@ -568,7 +518,7 @@ static int wait_for_ready(time_t timeout) ...@@ -568,7 +518,7 @@ static int wait_for_ready(time_t timeout)
*/ */
spin_t = 50; spin_t = 50;
while (((stat = inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK) && (--spin_t > 0)) while (((stat = inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK) && (--spin_t > 0))
/*SKIP*/; udelay(1);
if ((stat & QIC02_STAT_READY) == 0) if ((stat & QIC02_STAT_READY) == 0)
return TE_OK; /* covers 99.99% of all calls */ return TE_OK; /* covers 99.99% of all calls */
...@@ -580,9 +530,11 @@ static int wait_for_ready(time_t timeout) ...@@ -580,9 +530,11 @@ static int wait_for_ready(time_t timeout)
spin_t += jiffies; spin_t += jiffies;
/* FIXME...*/ /* FIXME...*/
while (((stat = inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK) while (((stat = inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK) && time_before(jiffies, spin_t))
&& time_before(jiffies, spin_t)) {
schedule(); /* don't waste all the CPU time */ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1); /* don't waste all the CPU time */
}
if ((stat & QIC02_STAT_READY) == 0) if ((stat & QIC02_STAT_READY) == 0)
return TE_OK; return TE_OK;
...@@ -611,8 +563,7 @@ static int wait_for_ready(time_t timeout) ...@@ -611,8 +563,7 @@ static int wait_for_ready(time_t timeout)
} }
if ((stat & QIC02_STAT_EXCEPTION) == 0) { if ((stat & QIC02_STAT_EXCEPTION) == 0) {
tpqputs(TPQD_ALWAYS, tpqputs(TPQD_ALWAYS, "exception detected after waiting_for_ready");
"exception detected after waiting_for_ready");
return TE_EX; return TE_EX;
} else { } else {
return TE_OK; return TE_OK;
...@@ -627,7 +578,6 @@ static int send_qic02_data(char sb[], unsigned size, int ignore_ex) ...@@ -627,7 +578,6 @@ static int send_qic02_data(char sb[], unsigned size, int ignore_ex)
int i, stat; int i, stat;
for (i = 0; i < size; i++) { for (i = 0; i < size; i++) {
stat = wait_for_ready(TIM_S); stat = wait_for_ready(TIM_S);
if (stat != TE_OK) if (stat != TE_OK)
return stat; return stat;
...@@ -700,9 +650,12 @@ static int rdstatus(char *stp, unsigned size, char qcmd) ...@@ -700,9 +650,12 @@ static int rdstatus(char *stp, unsigned size, char qcmd)
* de-schedule immediately, we waste a lot of time because a * de-schedule immediately, we waste a lot of time because a
* task switch is much longer than we usually have to wait here. * task switch is much longer than we usually have to wait here.
*/ */
n = 1000; /* 500 is not enough on a 486/33 */ n = 700;
while ((n > 0) && ((inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK)) while ((n > 0) && ((inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK))
{
udelay(1);
n--; /* wait for ready or exception or timeout */ n--; /* wait for ready or exception or timeout */
}
if (n == 0) { if (n == 0) {
/* n (above) should be chosen such that on your machine /* n (above) should be chosen such that on your machine
* you rarely ever see the message below, and it should * you rarely ever see the message below, and it should
...@@ -711,7 +664,10 @@ static int rdstatus(char *stp, unsigned size, char qcmd) ...@@ -711,7 +664,10 @@ static int rdstatus(char *stp, unsigned size, char qcmd)
/* FIXME */ /* FIXME */
tpqputs(TPQD_ALWAYS, "waiting looong in rdstatus() -- drive dead?"); tpqputs(TPQD_ALWAYS, "waiting looong in rdstatus() -- drive dead?");
while ((inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK) while ((inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK)
schedule(); {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
}
tpqputs(TPQD_ALWAYS, "finished waiting in rdstatus()"); tpqputs(TPQD_ALWAYS, "finished waiting in rdstatus()");
} }
...@@ -737,12 +693,12 @@ static int rdstatus(char *stp, unsigned size, char qcmd) ...@@ -737,12 +693,12 @@ static int rdstatus(char *stp, unsigned size, char qcmd)
*q = inb_p(QIC02_DATA_PORT); /* read status byte */ *q = inb_p(QIC02_DATA_PORT); /* read status byte */
if (TP_DIAGS(current_tape_dev)) if (TP_DIAGS(current_tape_dev))
printk("[%1d]=0x%x ", q - stp, printk("[%1d]=0x%x ", q - stp, (unsigned) (*q) & 0xff);
(unsigned) (*q) & 0xff);
outb_p(ctlbits | QIC02_CTL_REQUEST, QIC02_CTL_PORT); /* set request */ outb_p(ctlbits | QIC02_CTL_REQUEST, QIC02_CTL_PORT); /* set request */
while ((inb_p(QIC02_STAT_PORT) & QIC02_STAT_READY) == 0); /* wait for not ready */ while ((inb_p(QIC02_STAT_PORT) & QIC02_STAT_READY) == 0)
cpu_relax(); /* wait for not ready */
udelay(22); /* delay >20 usec */ udelay(22); /* delay >20 usec */
...@@ -754,7 +710,7 @@ static int rdstatus(char *stp, unsigned size, char qcmd) ...@@ -754,7 +710,7 @@ static int rdstatus(char *stp, unsigned size, char qcmd)
* My drive doesn't seem to need it here yet, but others do? * My drive doesn't seem to need it here yet, but others do?
*/ */
while (inb_p(QIC02_STAT_PORT) & QIC02_STAT_READY) while (inb_p(QIC02_STAT_PORT) & QIC02_STAT_READY)
/*skip */ ; cpu_relax();
/* wait for ready */ /* wait for ready */
if (TP_DIAGS(current_tape_dev)) if (TP_DIAGS(current_tape_dev))
...@@ -772,13 +728,8 @@ static int rdstatus(char *stp, unsigned size, char qcmd) ...@@ -772,13 +728,8 @@ static int rdstatus(char *stp, unsigned size, char qcmd)
static int get_status(volatile struct tpstatus *stp) static int get_status(volatile struct tpstatus *stp)
{ {
int stat = rdstatus((char *) stp, TPSTATSIZE, QCMD_RD_STAT); int stat = rdstatus((char *) stp, TPSTATSIZE, QCMD_RD_STAT);
#if defined(__i386__) || defined (__x86_64__) stp->dec = be16_to_cpu(stp->dec);
byte_swap_w(&(stp->dec)); stp->urc = be16_to_cpu(stp->urc);
byte_swap_w(&(stp->urc));
#else
#warning Undefined architecture
/* should probably swap status bytes #definition */
#endif
return stat; return stat;
} /* get_status */ } /* get_status */
...@@ -823,8 +774,7 @@ static int tp_sense(int ignore) ...@@ -823,8 +774,7 @@ static int tp_sense(int ignore)
static void finish_rw(int cmd); static void finish_rw(int cmd);
if (TPQDBG(SENSE_TEXT)) if (TPQDBG(SENSE_TEXT))
printk(TPQIC02_NAME ": tp_sense(ignore=0x%x) enter\n", printk(TPQIC02_NAME ": tp_sense(ignore=0x%x) enter\n", ignore);
ignore);
/* sense() is not allowed during a read or write cycle */ /* sense() is not allowed during a read or write cycle */
if (doing_write == YES) if (doing_write == YES)
...@@ -842,11 +792,8 @@ static int tp_sense(int ignore) ...@@ -842,11 +792,8 @@ static int tp_sense(int ignore)
if (err & (TP_ST0 | TP_ST1)) if (err & (TP_ST0 | TP_ST1))
printk(TPQIC02_NAME ": tp_sense: status: %x, error count: %d, underruns: %d\n", printk(TPQIC02_NAME ": tp_sense: status: %x, error count: %d, underruns: %d\n",
tperror.exs, tperror.dec, tperror.urc); tperror.exs, tperror.dec, tperror.urc);
else if ((tperror.dec != 0) || (tperror.urc != 0) else if ((tperror.dec != 0) || (tperror.urc != 0) || TPQDBG(SENSE_CNTS))
|| TPQDBG(SENSE_CNTS)) printk(TPQIC02_NAME ": tp_sense: no hard errors, soft error count: %d, underruns: %d\n", tperror.dec, tperror.urc);
printk(TPQIC02_NAME
": tp_sense: no hard errors, soft error count: %d, underruns: %d\n",
tperror.dec, tperror.urc);
/* Set generic status. HP-UX defines these, but some extra would /* Set generic status. HP-UX defines these, but some extra would
* be useful. Problem is to remain compatible. [Do we want to be * be useful. Problem is to remain compatible. [Do we want to be
...@@ -909,9 +856,7 @@ static int wait_for_rewind(time_t timeout) ...@@ -909,9 +856,7 @@ static int wait_for_rewind(time_t timeout)
stat = inb(QIC02_STAT_PORT) & QIC02_STAT_MASK; stat = inb(QIC02_STAT_PORT) & QIC02_STAT_MASK;
if (TPQDBG(REWIND)) if (TPQDBG(REWIND))
printk(TPQIC02_NAME printk(TPQIC02_NAME ": Waiting for (re-)wind to finish: stat=0x%x\n", stat);
": Waiting for (re-)wind to finish: stat=0x%x\n",
stat);
stat = wait_for_ready(timeout); stat = wait_for_ready(timeout);
...@@ -946,13 +891,13 @@ static int ll_do_qic_cmd(int cmd, time_t timeout) ...@@ -946,13 +891,13 @@ static int ll_do_qic_cmd(int cmd, time_t timeout)
stat = TE_OK; stat = TE_OK;
} }
if (stat != TE_OK) { if (stat != TE_OK) {
printk(TPQIC02_NAME ": ll_do_qic_cmd(%x, %ld) failed\n", printk(TPQIC02_NAME ": ll_do_qic_cmd(%x, %ld) failed\n", cmd, (long) timeout);
cmd, (long) timeout);
return -EIO; return -EIO;
} }
#if OBSOLETE #if OBSOLETE
/* wait for ready since it may not be active immediately after reading status */ /* wait for ready since it may not be active immediately after reading status */
while ((inb_p(QIC02_STAT_PORT) & QIC02_STAT_READY) != 0); while ((inb_p(QIC02_STAT_PORT) & QIC02_STAT_READY) != 0)
cpu_relax();
#endif #endif
stat = send_qic02_cmd(cmd, timeout, 0); /* (checks for exceptions) */ stat = send_qic02_cmd(cmd, timeout, 0); /* (checks for exceptions) */
...@@ -982,21 +927,16 @@ static int ll_do_qic_cmd(int cmd, time_t timeout) ...@@ -982,21 +927,16 @@ static int ll_do_qic_cmd(int cmd, time_t timeout)
/* sense() will set eof/eom as required */ /* sense() will set eof/eom as required */
if (stat == TE_EX) { if (stat == TE_EX) {
if (tp_sense(TP_WRP | TP_BOM | TP_EOM | TP_FIL) != TE_OK) { if (tp_sense(TP_WRP | TP_BOM | TP_EOM | TP_FIL) != TE_OK) {
printk(TPQIC02_NAME printk(TPQIC02_NAME ": Exception persist in ll_do_qic_cmd[1](%x, %ld)", cmd, (long) timeout);
": Exception persist in ll_do_qic_cmd[1](%x, %ld)",
cmd, (long) timeout);
status_dead = YES; status_dead = YES;
return -ENXIO; return -ENXIO;
/* if rdstatus fails too, we're in trouble */ /* if rdstatus fails too, we're in trouble */
} }
} else if (stat != TE_OK) { } else if (stat != TE_OK) {
printk(TPQIC02_NAME printk(TPQIC02_NAME ": ll_do_qic_cmd: send_qic02_cmd failed, stat = 0x%x\n", stat);
": ll_do_qic_cmd: send_qic02_cmd failed, stat = 0x%x\n",
stat);
return -EIO; /*** -EIO is probably not always appropriate */ return -EIO; /*** -EIO is probably not always appropriate */
} }
if (timeout == TIM_R) if (timeout == TIM_R)
stat = wait_for_rewind(timeout); stat = wait_for_rewind(timeout);
else else
...@@ -1007,18 +947,14 @@ static int ll_do_qic_cmd(int cmd, time_t timeout) ...@@ -1007,18 +947,14 @@ static int ll_do_qic_cmd(int cmd, time_t timeout)
TP_EOR | TP_NDT | TP_UDA | TP_BNL | TP_WRP | TP_EOR | TP_NDT | TP_UDA | TP_BNL | TP_WRP |
TP_BOM | TP_EOM | TP_FIL : TP_WRP | TP_BOM | TP_BOM | TP_EOM | TP_FIL : TP_WRP | TP_BOM |
TP_EOM | TP_FIL)) != TE_OK) { TP_EOM | TP_FIL)) != TE_OK) {
printk(TPQIC02_NAME printk(TPQIC02_NAME ": Exception persist in ll_do_qic_cmd[2](%x, %ld)\n", cmd, (long) timeout);
": Exception persist in ll_do_qic_cmd[2](%x, %ld)\n",
cmd, (long) timeout);
if (cmd != QCMD_RD_FM) if (cmd != QCMD_RD_FM)
status_dead = YES; status_dead = YES;
return -ENXIO; return -ENXIO;
/* if rdstatus fails too, we're in trouble */ /* if rdstatus fails too, we're in trouble */
} }
} else if (stat != TE_OK) { } else if (stat != TE_OK) {
printk(TPQIC02_NAME printk(TPQIC02_NAME ": ll_do_qic_cmd %x: wait failed, stat == 0x%x\n", cmd, stat);
": ll_do_qic_cmd %x: wait failed, stat == 0x%x\n",
cmd, stat);
return -EIO; return -EIO;
} }
return 0; return 0;
...@@ -1052,30 +988,30 @@ static int ll_do_qic_cmd(int cmd, time_t timeout) ...@@ -1052,30 +988,30 @@ static int ll_do_qic_cmd(int cmd, time_t timeout)
static void terminate_read(int cmd) static void terminate_read(int cmd)
{ {
if (doing_read == YES) { if (doing_read != YES)
doing_read = NO; return;
if (cmd != QCMD_RD_FM) {
/* if the command is a RFM, there is no need to do this doing_read = NO;
* because a RFM will legally terminate the read-cycle.
*/ if (cmd == QCMD_RD_FM)
tpqputs(TPQD_ALWAYS, "terminating pending read-cycle"); return;
/* if the command is a RFM, there is no need to do this
* because a RFM will legally terminate the read-cycle.
*/
tpqputs(TPQD_ALWAYS, "terminating pending read-cycle");
/* I'm not too sure about this part -- hhb */ /* I'm not too sure about this part -- hhb */
if (QIC02_TAPE_IFC == MOUNTAIN) { if (QIC02_TAPE_IFC == MOUNTAIN) {
/* Mountain reference says can terminate by de-asserting online */ /* Mountain reference says can terminate by de-asserting online */
ctlbits &= ~MTN_QIC02_CTL_ONLINE; ctlbits &= ~MTN_QIC02_CTL_ONLINE;
} }
if (tp_sense(TP_FIL | TP_EOM | TP_WRP) != TE_OK) { if (tp_sense(TP_FIL | TP_EOM | TP_WRP) != TE_OK) {
tpqputs(TPQD_ALWAYS, tpqputs(TPQD_ALWAYS, "finish_rw[read1]: ignore the 2 lines above");
"finish_rw[read1]: ignore the 2 lines above"); if (is_exception()) {
if (is_exception()) { if (tp_sense(TP_ILL | TP_FIL | TP_EOM | TP_WRP) != TE_OK)
if (tp_sense tpqputs(TPQD_ALWAYS,"finish_rw[read2]: read cycle error");
(TP_ILL | TP_FIL | TP_EOM |
TP_WRP) != TE_OK)
tpqputs(TPQD_ALWAYS,"finish_rw[read2]: read cycle error");
}
}
} }
} }
} /* terminate_read */ } /* terminate_read */
...@@ -1085,23 +1021,23 @@ static void terminate_write(int cmd) ...@@ -1085,23 +1021,23 @@ static void terminate_write(int cmd)
{ {
int stat; int stat;
if (doing_write == YES) { if (doing_write != YES)
doing_write = NO; return;
/* Finish writing by appending a FileMark at the end. */
if (cmd != QCMD_WRT_FM) { doing_write = NO;
/* finish off write cycle */ /* Finish writing by appending a FileMark at the end. */
stat = ll_do_qic_cmd(QCMD_WRT_FM, TIM_M); if (cmd != QCMD_WRT_FM) {
if (stat != TE_OK) /* finish off write cycle */
tpqputs(TPQD_ALWAYS, stat = ll_do_qic_cmd(QCMD_WRT_FM, TIM_M);
"Couldn't finish write cycle properly"); if (stat != TE_OK)
(void) tp_sense(0); tpqputs(TPQD_ALWAYS, "Couldn't finish write cycle properly");
} (void) tp_sense(0);
/* If there is an EOF token waiting to be returned to
* the (writing) application, discard it now.
* We could be at EOT, so don't reset return_write_eof.
*/
reported_write_eof = YES;
} }
/* If there is an EOF token waiting to be returned to
* the (writing) application, discard it now.
* We could be at EOT, so don't reset return_write_eof.
*/
reported_write_eof = YES;
} /* terminate_write */ } /* terminate_write */
...@@ -1109,8 +1045,7 @@ static void terminate_write(int cmd) ...@@ -1109,8 +1045,7 @@ static void terminate_write(int cmd)
static void finish_rw(int cmd) static void finish_rw(int cmd)
{ {
if (wait_for_ready(TIM_S) != TE_OK) { if (wait_for_ready(TIM_S) != TE_OK) {
tpqputs(TPQD_ALWAYS, tpqputs(TPQD_ALWAYS, "error: drive not ready in finish_rw() !");
"error: drive not ready in finish_rw() !");
return; return;
} }
terminate_read(cmd); terminate_read(cmd);
...@@ -1172,8 +1107,7 @@ static int do_ioctl_cmd(int cmd) ...@@ -1172,8 +1107,7 @@ static int do_ioctl_cmd(int cmd)
case MTBSF: case MTBSF:
if (TP_HAVE_BSF) { if (TP_HAVE_BSF) {
tpqputs(TPQD_IOCTLS, tpqputs(TPQD_IOCTLS, "MTBSF backward searching filemark -- optional command");
"MTBSF backward searching filemark -- optional command");
if ((mode_access == WRITE) && status_bytes_wr) if ((mode_access == WRITE) && status_bytes_wr)
return -EACCES; return -EACCES;
stat = do_qic_cmd(QCMD_RD_FM_BCK, TIM_F); stat = do_qic_cmd(QCMD_RD_FM_BCK, TIM_F);
...@@ -1243,7 +1177,7 @@ static int do_ioctl_cmd(int cmd) ...@@ -1243,7 +1177,7 @@ static int do_ioctl_cmd(int cmd)
case MTNOP: case MTNOP:
tpqputs(TPQD_IOCTLS, "MTNOP setting status only"); tpqputs(TPQD_IOCTLS, "MTNOP setting status only");
/********** should do `read position' for drives that support it **********/ /********** should do `read position' for drives that support it **********/
return (tp_sense(-1) == TE_OK) ? 0 : -EIO; /**** check return codes ****/ return (tp_sense(-1) == TE_OK) ? 0 : -EIO; /**** check return codes ****/
case MTRETEN: case MTRETEN:
...@@ -1377,12 +1311,7 @@ static int do_ioctl_cmd(int cmd) ...@@ -1377,12 +1311,7 @@ static int do_ioctl_cmd(int cmd)
/* dma_transfer(): This routine is called for every 512 bytes to be read /* dma_transfer(): This routine is called for every 512 bytes to be read
* from/written to the tape controller. Speed is important here! * from/written to the tape controller. Speed is important here!
* (There must be enough time left for the hd controller!) * (There must be enough time left for the hd controller!)
* When other devices use DMA they must ensure they use un-interruptible * The dma lock protects the DMA controller
* double byte accesses to the DMA controller. Floppy.c is ok.
* Must have interrupts disabled when this function is invoked,
* otherwise, the double-byte transfers to the DMA controller will not
* be atomic. That could lead to nasty problems when they are interrupted
* by other DMA interrupt-routines.
* *
* This routine merely does the least possible to keep * This routine merely does the least possible to keep
* the transfers going: * the transfers going:
...@@ -1407,8 +1336,7 @@ static inline void dma_transfer(void) ...@@ -1407,8 +1336,7 @@ static inline void dma_transfer(void)
flags = claim_dma_lock(); flags = claim_dma_lock();
clear_dma_ff(QIC02_TAPE_DMA); clear_dma_ff(QIC02_TAPE_DMA);
set_dma_mode(QIC02_TAPE_DMA, dma_mode); set_dma_mode(QIC02_TAPE_DMA, dma_mode);
set_dma_addr(QIC02_TAPE_DMA, set_dma_addr(QIC02_TAPE_DMA, isa_virt_to_bus(buffaddr) + dma_bytes_done);
isa_virt_to_bus(buffaddr) + dma_bytes_done);
set_dma_count(QIC02_TAPE_DMA, TAPE_BLKSIZE); set_dma_count(QIC02_TAPE_DMA, TAPE_BLKSIZE);
/* start tape DMA controller */ /* start tape DMA controller */
...@@ -1452,13 +1380,12 @@ static int start_dma(short mode, unsigned long bytes_todo) ...@@ -1452,13 +1380,12 @@ static int start_dma(short mode, unsigned long bytes_todo)
/* assume 'bytes_todo'>0 */ /* assume 'bytes_todo'>0 */
{ {
int stat; int stat;
unsigned long flags;
tpqputs(TPQD_DEBUG, "start_dma() enter"); tpqputs(TPQD_DEBUG, "start_dma() enter");
TPQDEB( {printk(TPQIC02_NAME ": doing_read==%d, doing_write==%d\n", TPQDEB( {printk(TPQIC02_NAME ": doing_read==%d, doing_write==%d\n",
doing_read, doing_write);}) doing_read, doing_write);})
dma_bytes_done = 0; dma_bytes_done = 0;
dma_bytes_todo = bytes_todo; dma_bytes_todo = bytes_todo;
status_error = NO; status_error = NO;
/* dma_mode!=0 indicates that the dma controller is in use */ /* dma_mode!=0 indicates that the dma controller is in use */
...@@ -1484,17 +1411,14 @@ static int start_dma(short mode, unsigned long bytes_todo) ...@@ -1484,17 +1411,14 @@ static int start_dma(short mode, unsigned long bytes_todo)
/* TP_CNI should now be handled in open(). -Hennus */ /* TP_CNI should now be handled in open(). -Hennus */
#endif #endif
stat = stat = tp_sense(((mode == WRITE) ? 0 : TP_WRP) | TP_BOM | TP_FIL);
tp_sense(((mode ==
WRITE) ? 0 : TP_WRP) | TP_BOM | TP_FIL);
if (stat != TE_OK) if (stat != TE_OK)
return stat; return stat;
#if OBSOLETE #if OBSOLETE
/************* not needed iff rd_status() would wait for ready!!!!!! **********/ /************* not needed iff rd_status() would wait for ready!!!!!! **********/
if (wait_for_ready(TIM_S) != TE_OK) { /*** not sure this is needed ***/ if (wait_for_ready(TIM_S) != TE_OK) { /*** not sure this is needed ***/
tpqputs(TPQD_ALWAYS, tpqputs(TPQD_ALWAYS, "wait_for_ready failed in start_dma");
"wait_for_ready failed in start_dma");
return -EIO; return -EIO;
} }
#endif #endif
...@@ -1507,11 +1431,9 @@ static int start_dma(short mode, unsigned long bytes_todo) ...@@ -1507,11 +1431,9 @@ static int start_dma(short mode, unsigned long bytes_todo)
/* Tell the controller the data direction */ /* Tell the controller the data direction */
/* r/w, timeout medium, check exceptions, sets status_cmd_pending. */ /* r/w, timeout medium, check exceptions, sets status_cmd_pending. */
stat = send_qic02_cmd((mode == WRITE) stat = send_qic02_cmd((mode == WRITE) ? QCMD_WRT_DATA : QCMD_RD_DATA, TIM_M, 0);
? QCMD_WRT_DATA : QCMD_RD_DATA, TIM_M, 0);
if (stat != TE_OK) { if (stat != TE_OK) {
printk(TPQIC02_NAME ": start_dma: init %s failed\n", printk(TPQIC02_NAME ": start_dma: init %s failed\n", (mode == WRITE) ? "write" : "read");
(mode == WRITE) ? "write" : "read");
(void) tp_sense(0); (void) tp_sense(0);
return stat; return stat;
} }
...@@ -1529,10 +1451,8 @@ static int start_dma(short mode, unsigned long bytes_todo) ...@@ -1529,10 +1451,8 @@ static int start_dma(short mode, unsigned long bytes_todo)
doing_write = YES; doing_write = YES;
break; break;
default: default:
printk(TPQIC02_NAME printk(TPQIC02_NAME ": requested unknown mode %d\n", mode);
": requested unknown mode %d\n", mode); panic(TPQIC02_NAME ": invalid mode in start_dma()");
panic(TPQIC02_NAME
": invalid mode in start_dma()");
} }
} else if (is_exception()) { } else if (is_exception()) {
...@@ -1541,8 +1461,7 @@ static int start_dma(short mode, unsigned long bytes_todo) ...@@ -1541,8 +1461,7 @@ static int start_dma(short mode, unsigned long bytes_todo)
* *
* ******** this also affects EOF/EOT handling! ************ * ******** this also affects EOF/EOT handling! ************
*/ */
tpqputs(TPQD_ALWAYS, tpqputs(TPQD_ALWAYS, "detected exception in start_dma() while transfer in progress");
"detected exception in start_dma() while transfer in progress");
status_error = YES; status_error = YES;
return TE_END; return TE_END;
} }
...@@ -1557,10 +1476,7 @@ static int start_dma(short mode, unsigned long bytes_todo) ...@@ -1557,10 +1476,7 @@ static int start_dma(short mode, unsigned long bytes_todo)
/* initiate first data block read from/write to the tape controller */ /* initiate first data block read from/write to the tape controller */
save_flags(flags);
cli();
dma_transfer(); dma_transfer();
restore_flags(flags);
TPQPUTS("start_dma() end"); TPQPUTS("start_dma() end");
return TE_OK; return TE_OK;
...@@ -1594,7 +1510,6 @@ static void end_dma(unsigned long *bytes_done) ...@@ -1594,7 +1510,6 @@ static void end_dma(unsigned long *bytes_done)
else if (QIC02_TAPE_IFC == ARCHIVE) else if (QIC02_TAPE_IFC == ARCHIVE)
outb_p(0, AR_RESET_DMA_PORT); outb_p(0, AR_RESET_DMA_PORT);
else { /* QIC02_TAPE_IFC == MOUNTAIN */ else { /* QIC02_TAPE_IFC == MOUNTAIN */
/* Clear control bits, de-select ONLINE during tp_sense */ /* Clear control bits, de-select ONLINE during tp_sense */
ctlbits &= ~MTN_QIC02_CTL_ONLINE; ctlbits &= ~MTN_QIC02_CTL_ONLINE;
} }
...@@ -1605,7 +1520,6 @@ static void end_dma(unsigned long *bytes_done) ...@@ -1605,7 +1520,6 @@ static void end_dma(unsigned long *bytes_done)
stat = tp_sense((dma_mode == READ) ? TP_WRP : 0); stat = tp_sense((dma_mode == READ) ? TP_WRP : 0);
/* no return here -- got to clean up first! */ /* no return here -- got to clean up first! */
} else { /* if (QIC02_TAPE_IFC == MOUNTAIN) */ } else { /* if (QIC02_TAPE_IFC == MOUNTAIN) */
outb_p(ctlbits, QIC02_CTL_PORT); outb_p(ctlbits, QIC02_CTL_PORT);
} }
...@@ -1718,8 +1632,7 @@ static void qic02_tape_interrupt(int irq, void *dev_id, ...@@ -1718,8 +1632,7 @@ static void qic02_tape_interrupt(int irq, void *dev_id,
* - something went wrong * - something went wrong
* So don't continue with the next block. * So don't continue with the next block.
*/ */
tpqputs(TPQD_ALWAYS, tpqputs(TPQD_ALWAYS, "isr: exception on tape controller");
"isr: exception on tape controller");
printk(" status %02x\n", stat); printk(" status %02x\n", stat);
status_error = TE_EX; status_error = TE_EX;
...@@ -1740,16 +1653,14 @@ static void qic02_tape_interrupt(int irq, void *dev_id, ...@@ -1740,16 +1653,14 @@ static void qic02_tape_interrupt(int irq, void *dev_id,
*/ */
if (QIC02_TAPE_IFC == WANGTEK) /* I think this is a drive-dependency, not IFC -- hhb */ if (QIC02_TAPE_IFC == WANGTEK) /* I think this is a drive-dependency, not IFC -- hhb */
if (stat & QIC02_STAT_READY) { /* not ready */ if (stat & QIC02_STAT_READY) { /* not ready */
tpqputs(TPQD_ALWAYS, tpqputs(TPQD_ALWAYS, "isr: ? Tape controller not ready");
"isr: ? Tape controller not ready");
r = 1; r = 1;
} }
flags = claim_dma_lock(); flags = claim_dma_lock();
if ((i = get_dma_residue(QIC02_TAPE_DMA)) != 0) { if ((i = get_dma_residue(QIC02_TAPE_DMA)) != 0) {
printk(TPQIC02_NAME ": dma_residue == %x !!!\n", printk(TPQIC02_NAME ": dma_residue == %x !!!\n", i);
i);
r = 1; /* big trouble, but can't do much about it... */ r = 1; /* big trouble, but can't do much about it... */
} }
...@@ -1774,8 +1685,7 @@ static void qic02_tape_interrupt(int irq, void *dev_id, ...@@ -1774,8 +1685,7 @@ static void qic02_tape_interrupt(int irq, void *dev_id,
dma_transfer(); dma_transfer();
} }
} else { } else {
printk(TPQIC02_NAME ": Unexpected interrupt, stat == %x\n", printk(TPQIC02_NAME ": Unexpected interrupt, stat == %x\n", inb(QIC02_STAT_PORT));
inb(QIC02_STAT_PORT));
} }
} /* qic02_tape_interrupt */ } /* qic02_tape_interrupt */
...@@ -1812,10 +1722,8 @@ static void qic02_tape_interrupt(int irq, void *dev_id, ...@@ -1812,10 +1722,8 @@ static void qic02_tape_interrupt(int irq, void *dev_id,
* request would return the EOF flag for the previous file. * request would return the EOF flag for the previous file.
*/ */
static ssize_t qic02_tape_read(struct file *filp, char *buf, size_t count, static ssize_t qic02_tape_read(struct file *filp, char *buf, size_t count, loff_t * ppos)
loff_t * ppos)
{ {
int err;
kdev_t dev = filp->f_dentry->d_inode->i_rdev; kdev_t dev = filp->f_dentry->d_inode->i_rdev;
unsigned short flags = filp->f_flags; unsigned short flags = filp->f_flags;
unsigned long bytes_todo, bytes_done, total_bytes_done = 0; unsigned long bytes_todo, bytes_done, total_bytes_done = 0;
...@@ -1827,11 +1735,8 @@ static ssize_t qic02_tape_read(struct file *filp, char *buf, size_t count, ...@@ -1827,11 +1735,8 @@ static ssize_t qic02_tape_read(struct file *filp, char *buf, size_t count,
} }
if (TP_DIAGS(current_tape_dev)) if (TP_DIAGS(current_tape_dev))
/* can't print a ``long long'' (for filp->f_pos), so chop it */ printk(TPQIC02_NAME ": request READ, minor=%x, buf=%p, count=%lx, pos=%Lx, flags=%x\n", minor(dev), buf,
printk(TPQIC02_NAME (long) count, filp->f_pos, flags);
": request READ, minor=%x, buf=%p, count=%lx"
", pos=%lx, flags=%x\n", minor(dev), buf,
(long) count, (unsigned long) filp->f_pos, flags);
if (count % TAPE_BLKSIZE) { /* Only allow mod 512 bytes at a time. */ if (count % TAPE_BLKSIZE) { /* Only allow mod 512 bytes at a time. */
tpqputs(TPQD_BLKSZ, "Wrong block size"); tpqputs(TPQD_BLKSZ, "Wrong block size");
...@@ -1858,10 +1763,7 @@ static ssize_t qic02_tape_read(struct file *filp, char *buf, size_t count, ...@@ -1858,10 +1763,7 @@ static ssize_t qic02_tape_read(struct file *filp, char *buf, size_t count,
/* Must ensure that user program sees exactly one EOF token (==0) */ /* Must ensure that user program sees exactly one EOF token (==0) */
if (return_read_eof == YES) { if (return_read_eof == YES) {
if (TPQDBG(DEBUG)) { if (TPQDBG(DEBUG)) {
printk printk("read: return_read_eof==%d, reported_read_eof==%d, total_bytes_done==%lu\n", return_read_eof, reported_read_eof, total_bytes_done);
("read: return_read_eof==%d, reported_read_eof==%d, total_bytes_done==%lu\n",
return_read_eof, reported_read_eof,
total_bytes_done);
} }
if (reported_read_eof == NO) { if (reported_read_eof == NO) {
...@@ -1897,7 +1799,6 @@ static ssize_t qic02_tape_read(struct file *filp, char *buf, size_t count, ...@@ -1897,7 +1799,6 @@ static ssize_t qic02_tape_read(struct file *filp, char *buf, size_t count,
} }
} }
/*****************************/
if (bytes_todo == 0) { if (bytes_todo == 0) {
return total_bytes_done; return total_bytes_done;
} }
...@@ -1905,9 +1806,7 @@ static ssize_t qic02_tape_read(struct file *filp, char *buf, size_t count, ...@@ -1905,9 +1806,7 @@ static ssize_t qic02_tape_read(struct file *filp, char *buf, size_t count,
if (bytes_todo > 0) { if (bytes_todo > 0) {
/* start reading data */ /* start reading data */
if (is_exception()) { if (is_exception()) {
/****************************************/ tpqputs(TPQD_DMAX, "is_exception() before start_dma()!");
tpqputs(TPQD_DMAX,
"is_exception() before start_dma()!");
} }
/****************************************************************** /******************************************************************
...@@ -1919,12 +1818,11 @@ static ssize_t qic02_tape_read(struct file *filp, char *buf, size_t count, ...@@ -1919,12 +1818,11 @@ static ssize_t qic02_tape_read(struct file *filp, char *buf, size_t count,
stat = start_dma(READ, bytes_todo); stat = start_dma(READ, bytes_todo);
if (stat == TE_OK) { if (stat == TE_OK) {
/* Wait for transfer to complete, interrupt should wake us */ /* Wait for transfer to complete, interrupt should wake us */
while (dma_mode != 0) {
sleep_on(&qic02_tape_transfer); wait_event(qic02_tape_transfer, dma_mode != 0);
}
if (status_error) { if (status_error)
return_read_eof = YES; return_read_eof = YES;
}
} else if (stat != TE_END) { } else if (stat != TE_END) {
/* should do sense() on error here */ /* should do sense() on error here */
...@@ -1938,8 +1836,7 @@ static ssize_t qic02_tape_read(struct file *filp, char *buf, size_t count, ...@@ -1938,8 +1836,7 @@ static ssize_t qic02_tape_read(struct file *filp, char *buf, size_t count,
} }
end_dma(&bytes_done); end_dma(&bytes_done);
if (bytes_done > bytes_todo) { if (bytes_done > bytes_todo) {
tpqputs(TPQD_ALWAYS, tpqputs(TPQD_ALWAYS, "read: Oops, read more bytes than requested");
"read: Oops, read more bytes than requested");
return -EIO; return -EIO;
} }
/* copy buffer to user-space in one go */ /* copy buffer to user-space in one go */
...@@ -1949,15 +1846,12 @@ static ssize_t qic02_tape_read(struct file *filp, char *buf, size_t count, ...@@ -1949,15 +1846,12 @@ static ssize_t qic02_tape_read(struct file *filp, char *buf, size_t count,
} }
#if 1 #if 1
/* Checks Ton's patch below */ /* Checks Ton's patch below */
if ((return_read_eof == NO) if ((return_read_eof == NO) && (status_eof_detected == YES)) {
&& (status_eof_detected == YES)) { printk(TPQIC02_NAME ": read(): return_read_eof=%d, status_eof_detected=YES. return_read_eof:=YES\n",
printk(TPQIC02_NAME
": read(): return_read_eof=%d, status_eof_detected=YES. return_read_eof:=YES\n",
return_read_eof); return_read_eof);
} }
#endif #endif
if ((bytes_todo != bytes_done) if ((bytes_todo != bytes_done) || (status_eof_detected == YES)) {
|| (status_eof_detected == YES)) {
/* EOF or EOM detected. return EOF next time. */ /* EOF or EOM detected. return EOF next time. */
return_read_eof = YES; return_read_eof = YES;
} }
...@@ -2006,10 +1900,8 @@ static ssize_t qic02_tape_read(struct file *filp, char *buf, size_t count, ...@@ -2006,10 +1900,8 @@ static ssize_t qic02_tape_read(struct file *filp, char *buf, size_t count,
* tape device again. The driver will detect an exception status in (No Cartridge) * tape device again. The driver will detect an exception status in (No Cartridge)
* and force a rewind. After that tar may continue writing. * and force a rewind. After that tar may continue writing.
*/ */
static ssize_t qic02_tape_write(struct file *filp, const char *buf, static ssize_t qic02_tape_write(struct file *filp, const char *buf, size_t count, loff_t * ppos)
size_t count, loff_t * ppos)
{ {
int err;
kdev_t dev = filp->f_dentry->d_inode->i_rdev; kdev_t dev = filp->f_dentry->d_inode->i_rdev;
unsigned short flags = filp->f_flags; unsigned short flags = filp->f_flags;
unsigned long bytes_todo, bytes_done, total_bytes_done = 0; unsigned long bytes_todo, bytes_done, total_bytes_done = 0;
...@@ -2020,11 +1912,8 @@ static ssize_t qic02_tape_write(struct file *filp, const char *buf, ...@@ -2020,11 +1912,8 @@ static ssize_t qic02_tape_write(struct file *filp, const char *buf,
} }
if (TP_DIAGS(current_tape_dev)) { if (TP_DIAGS(current_tape_dev)) {
/* can't print a ``long long'' (for filp->f_pos), so chop it */ printk(TPQIC02_NAME ": request WRITE, minor=%x, buf=%p, count=%lx, pos=%Lx, flags=%x\n",
printk(TPQIC02_NAME ": request WRITE, minor=%x, buf=%p" minor(dev), buf, (long) count, filp->f_pos, flags);
", count=%lx, pos=%lx, flags=%x\n",
minor(dev), buf,
(long) count, (unsigned long) filp->f_pos, flags);
} }
if (count % TAPE_BLKSIZE) { /* only allow mod 512 bytes at a time */ if (count % TAPE_BLKSIZE) { /* only allow mod 512 bytes at a time */
...@@ -2063,8 +1952,7 @@ static ssize_t qic02_tape_write(struct file *filp, const char *buf, ...@@ -2063,8 +1952,7 @@ static ssize_t qic02_tape_write(struct file *filp, const char *buf,
if (reported_write_eof == NO) { if (reported_write_eof == NO) {
if (bytes_todo > 0) { if (bytes_todo > 0) {
tpqputs(TPQD_ALWAYS, tpqputs(TPQD_ALWAYS, "partial write");
"partial write");
/* partial write signals EOF to user program */ /* partial write signals EOF to user program */
} }
reported_write_eof = YES; reported_write_eof = YES;
...@@ -2091,22 +1979,18 @@ static ssize_t qic02_tape_write(struct file *filp, const char *buf, ...@@ -2091,22 +1979,18 @@ static ssize_t qic02_tape_write(struct file *filp, const char *buf,
***** fail and write() will return ENXIO error ***** fail and write() will return ENXIO error
*****/ *****/
if (start_dma(WRITE, bytes_todo) != TE_OK) { if (start_dma(WRITE, bytes_todo) != TE_OK) {
tpqputs(TPQD_ALWAYS, tpqputs(TPQD_ALWAYS, "write: start_dma() failed");
"write: start_dma() failed");
/* should do sense() on error here */ /* should do sense() on error here */
return -ENXIO; return -ENXIO;
/*********** FIXTHIS **************/ /*********** FIXTHIS **************/
} }
/* Wait for write to complete, interrupt should wake us. */ /* Wait for write to complete, interrupt should wake us. */
while ((status_error == 0) && (dma_mode != 0)) { wait_event(qic02_tape_transfer, (status_error == 0 && dma_mode != 0));
sleep_on(&qic02_tape_transfer);
}
end_dma(&bytes_done); end_dma(&bytes_done);
if (bytes_done > bytes_todo) { if (bytes_done > bytes_todo) {
tpqputs(TPQD_ALWAYS, tpqputs(TPQD_ALWAYS, "write: Oops, wrote more bytes than requested");
"write: Oops, wrote more bytes than requested");
return -EIO; return -EIO;
} }
/* If the dma-transfer was aborted because of an exception, /* If the dma-transfer was aborted because of an exception,
...@@ -2123,13 +2007,11 @@ static ssize_t qic02_tape_write(struct file *filp, const char *buf, ...@@ -2123,13 +2007,11 @@ static ssize_t qic02_tape_write(struct file *filp, const char *buf,
*/ */
if (status_error) { if (status_error) {
if (status_eom_detected == YES) { if (status_eom_detected == YES) {
tpqputs(TPQD_ALWAYS, tpqputs(TPQD_ALWAYS, "write: EW detected");
"write: EW detected");
return_write_eof = YES; return_write_eof = YES;
} else { } else {
/* probably EXC_RWA */ /* probably EXC_RWA */
tpqputs(TPQD_ALWAYS, tpqputs(TPQD_ALWAYS, "write: dma: error in writing");
"write: dma: error in writing");
return -EIO; return -EIO;
} }
} }
...@@ -2193,8 +2075,7 @@ static int qic02_tape_open_no_use_count(struct inode *inode, ...@@ -2193,8 +2075,7 @@ static int qic02_tape_open_no_use_count(struct inode *inode,
if (TP_DIAGS(dev)) { if (TP_DIAGS(dev)) {
printk("qic02_tape_open: dev=%s, flags=%x ", printk("qic02_tape_open: dev=%s, flags=%x ", kdevname(dev), flags);
kdevname(dev), flags);
} }
if (minor(dev) == 255) { /* special case for resetting */ if (minor(dev) == 255) { /* special case for resetting */
...@@ -2210,11 +2091,9 @@ static int qic02_tape_open_no_use_count(struct inode *inode, ...@@ -2210,11 +2091,9 @@ static int qic02_tape_open_no_use_count(struct inode *inode,
return 0; return 0;
} }
/* Only one at a time from here on... */ if(test_and_set_bit(0, &tape_open))
if (file_count(filp) > 1) { /* filp->f_count==1 for the first open() */
return -EBUSY; return -EBUSY;
}
if (status_zombie == YES) { if (status_zombie == YES) {
/* no irq/dma/port stuff allocated yet, no reset done /* no irq/dma/port stuff allocated yet, no reset done
* yet, so return until MTSETCONFIG has been done. * yet, so return until MTSETCONFIG has been done.
...@@ -2256,13 +2135,13 @@ static int qic02_tape_open_no_use_count(struct inode *inode, ...@@ -2256,13 +2135,13 @@ static int qic02_tape_open_no_use_count(struct inode *inode,
if (s == TE_OK) { if (s == TE_OK) {
/* Try to clear cartridge-changed status for Archive-2150L */ /* Try to clear cartridge-changed status for Archive-2150L */
if ((tperror.exs & TP_ST0) && (tperror.exs & TP_CNI)) { if ((tperror.exs & TP_ST0) && (tperror.exs & TP_CNI)) {
s = tp_sense(TP_WRP | TP_EOM | TP_BOM | TP_CNI | s = tp_sense(TP_WRP | TP_EOM | TP_BOM | TP_CNI | TP_EOR);
TP_EOR);
} }
} }
if (s != TE_OK) { if (s != TE_OK) {
tpqputs(TPQD_ALWAYS, "open: sense() failed"); tpqputs(TPQD_ALWAYS, "open: sense() failed");
clear_bit(0, &tape_open);
return -EIO; return -EIO;
} }
...@@ -2272,6 +2151,7 @@ static int qic02_tape_open_no_use_count(struct inode *inode, ...@@ -2272,6 +2151,7 @@ static int qic02_tape_open_no_use_count(struct inode *inode,
*/ */
if ((tperror.exs & TP_ST0) && (tperror.exs & TP_CNI)) { if ((tperror.exs & TP_ST0) && (tperror.exs & TP_CNI)) {
tpqputs(TPQD_ALWAYS, "No tape present."); tpqputs(TPQD_ALWAYS, "No tape present.");
clear_bit(0, &tape_open);
return -EIO; return -EIO;
} }
...@@ -2280,15 +2160,13 @@ static int qic02_tape_open_no_use_count(struct inode *inode, ...@@ -2280,15 +2160,13 @@ static int qic02_tape_open_no_use_count(struct inode *inode,
*/ */
/* not allowed to do QCMD_DENS_* unless tape is rewound */ /* not allowed to do QCMD_DENS_* unless tape is rewound */
if ((TP_DENS(dev) != 0) if ((TP_DENS(dev) != 0) && (TP_DENS(current_tape_dev) != TP_DENS(dev))) {
&& (TP_DENS(current_tape_dev) != TP_DENS(dev))) {
/* force rewind if minor bits have changed, /* force rewind if minor bits have changed,
* i.e. user wants to use tape in different format. * i.e. user wants to use tape in different format.
* [assuming single drive operation] * [assuming single drive operation]
*/ */
if (TP_HAVE_DENS) { if (TP_HAVE_DENS) {
tpqputs(TPQD_REWIND, tpqputs(TPQD_REWIND, "Density minor bits have changed. Forcing rewind.");
"Density minor bits have changed. Forcing rewind.");
need_rewind = YES; need_rewind = YES;
} }
} else { } else {
...@@ -2318,8 +2196,7 @@ static int qic02_tape_open_no_use_count(struct inode *inode, ...@@ -2318,8 +2196,7 @@ static int qic02_tape_open_no_use_count(struct inode *inode,
} else { } else {
status_dead = NO; status_dead = NO;
if (tp_sense(~(TP_ST1 | TP_ILL)) != TE_OK) { if (tp_sense(~(TP_ST1 | TP_ILL)) != TE_OK) {
tpqputs(TPQD_ALWAYS, tpqputs(TPQD_ALWAYS, "open: tp_sense() failed\n");
"open: tp_sense() failed\n");
status_dead = YES; /* try reset next time */ status_dead = YES; /* try reset next time */
return -EIO; return -EIO;
} }
...@@ -2343,12 +2220,10 @@ static int qic02_tape_open_no_use_count(struct inode *inode, ...@@ -2343,12 +2220,10 @@ static int qic02_tape_open_no_use_count(struct inode *inode,
dens = TP_DENS(dev); dens = TP_DENS(dev);
} }
if (dens < sizeof(format_names) / sizeof(char *)) { if (dens < sizeof(format_names) / sizeof(char *))
printk(TPQIC02_NAME ": format: %s%s\n", printk(TPQIC02_NAME ": format: %s%s\n", (dens != 0) ? "QIC-" : "", format_names[dens]);
(dens != 0) ? "QIC-" : "", format_names[dens]); else
} else {
tpqputs(TPQD_REWIND, "Wait for retensioning..."); tpqputs(TPQD_REWIND, "Wait for retensioning...");
}
switch (TP_DENS(dev)) { switch (TP_DENS(dev)) {
case 0: /* Minor 0 is for drives without set-density support */ case 0: /* Minor 0 is for drives without set-density support */
...@@ -2406,12 +2281,12 @@ static int qic02_tape_release(struct inode *inode, struct file *filp) ...@@ -2406,12 +2281,12 @@ static int qic02_tape_release(struct inode *inode, struct file *filp)
/* Rewind only if minor number requires it AND /* Rewind only if minor number requires it AND
* read/writes have been done. ************* IS THIS CORRECT?????????? * read/writes have been done. ************* IS THIS CORRECT??????????
*/ */
if ((TP_REWCLOSE(dev)) if ((TP_REWCLOSE(dev)) && (status_bytes_rd | status_bytes_wr)) {
&& (status_bytes_rd | status_bytes_wr)) {
tpqputs(TPQD_REWIND, "release: Doing rewind..."); tpqputs(TPQD_REWIND, "release: Doing rewind...");
(void) do_qic_cmd(QCMD_REWIND, TIM_R); (void) do_qic_cmd(QCMD_REWIND, TIM_R);
} }
} }
clear_bit(0, &tape_open);
return 0; return 0;
} /* qic02_tape_release */ } /* qic02_tape_release */
...@@ -2512,47 +2387,32 @@ static int update_ifc_masks(int ifc) ...@@ -2512,47 +2387,32 @@ static int update_ifc_masks(int ifc)
/* ioctl allows user programs to rewind the tape and stuff like that */ /* ioctl allows user programs to rewind the tape and stuff like that */
static int qic02_tape_ioctl(struct inode *inode, struct file *filp, static int qic02_tape_ioctl(struct inode *inode, struct file *filp, unsigned int iocmd, unsigned long ioarg)
unsigned int iocmd, unsigned long ioarg)
{ {
int error; int error;
int dev_maj = major(inode->i_rdev);
int c; int c;
struct mtop operation; struct mtop operation;
unsigned char blk_addr[6]; unsigned char blk_addr[6];
struct mtpos ioctl_tell; struct mtpos ioctl_tell;
if (TP_DIAGS(current_tape_dev)) { if (TP_DIAGS(current_tape_dev))
printk(TPQIC02_NAME ": ioctl(%4x, %4x, %4lx)\n", dev_maj, printk(TPQIC02_NAME ": ioctl(%4x, %4lx)\n", iocmd, ioarg);
iocmd, ioarg);
}
if (!inode || !ioarg) { if (!inode)
return -EINVAL; return -EINVAL;
}
/* check iocmd first */ /* check iocmd first */
if (dev_maj != QIC02_TAPE_MAJOR) {
printk(TPQIC02_NAME ": Oops! Wrong device?\n");
/* A panic() would be appropriate here */
return -ENODEV;
}
c = _IOC_NR(iocmd); c = _IOC_NR(iocmd);
#ifdef CONFIG_QIC02_DYNCONF #ifdef CONFIG_QIC02_DYNCONF
if (c == _IOC_NR(MTIOCGETCONFIG)) { if (c == _IOC_NR(MTIOCGETCONFIG)) {
CHECK_IOC_SIZE(mtconfiginfo); CHECK_IOC_SIZE(mtconfiginfo);
if (copy_to_user if (copy_to_user((char *) ioarg, (char *) &qic02_tape_dynconf, sizeof(qic02_tape_dynconf)))
((char *) ioarg, (char *) &qic02_tape_dynconf,
sizeof(qic02_tape_dynconf))) {
return -EFAULT; return -EFAULT;
}
return 0; return 0;
} else if (c == _IOC_NR(MTIOCSETCONFIG)) { } else if (c == _IOC_NR(MTIOCSETCONFIG)) {
/* One should always do a MTIOCGETCONFIG first, then update /* One should always do a MTIOCGETCONFIG first, then update
* user-settings, then write back with MTIOCSETCONFIG. * user-settings, then write back with MTIOCSETCONFIG.
...@@ -2562,24 +2422,19 @@ static int qic02_tape_ioctl(struct inode *inode, struct file *filp, ...@@ -2562,24 +2422,19 @@ static int qic02_tape_ioctl(struct inode *inode, struct file *filp,
CHECK_IOC_SIZE(mtconfiginfo); CHECK_IOC_SIZE(mtconfiginfo);
if (!capable(CAP_SYS_ADMIN)) { if (!capable(CAP_SYS_RAWIO))
return -EPERM; return -EPERM;
}
if ((doing_read != NO) || (doing_write != NO)) { if (doing_read != NO || doing_write != NO)
return -EBUSY; return -EBUSY;
}
if (status_zombie == NO) { if (status_zombie == NO)
qic02_release_resources(); /* and go zombie */ qic02_release_resources(); /* and go zombie */
}
/* copy struct from user space to kernel space */ /* copy struct from user space to kernel space */
if (copy_from_user if (copy_from_user((char *) &qic02_tape_dynconf, (char *) ioarg, sizeof(qic02_tape_dynconf)))
((char *) &qic02_tape_dynconf, (char *) ioarg,
sizeof(qic02_tape_dynconf))) {
return -EFAULT; return -EFAULT;
}
return update_ifc_masks(qic02_tape_dynconf.ifc_type); return update_ifc_masks(qic02_tape_dynconf.ifc_type);
} }
if (status_zombie == YES) { if (status_zombie == YES) {
...@@ -2591,11 +2446,8 @@ static int qic02_tape_ioctl(struct inode *inode, struct file *filp, ...@@ -2591,11 +2446,8 @@ static int qic02_tape_ioctl(struct inode *inode, struct file *filp,
CHECK_IOC_SIZE(mtop); CHECK_IOC_SIZE(mtop);
/* copy mtop struct from user space to kernel space */ /* copy mtop struct from user space to kernel space */
if (copy_from_user if (copy_from_user((char *) &operation, (char *) ioarg, sizeof(operation)))
((char *) &operation, (char *) ioarg,
sizeof(operation))) {
return -EFAULT; return -EFAULT;
}
/* ---note: mt_count is signed, negative seeks must be /* ---note: mt_count is signed, negative seeks must be
* --- translated to seeks in opposite direction! * --- translated to seeks in opposite direction!
...@@ -2605,42 +2457,32 @@ static int qic02_tape_ioctl(struct inode *inode, struct file *filp, ...@@ -2605,42 +2457,32 @@ static int qic02_tape_ioctl(struct inode *inode, struct file *filp,
* --- tape at the beginning of the current file. * --- tape at the beginning of the current file.
*/ */
if (TP_DIAGS(current_tape_dev)) { if (TP_DIAGS(current_tape_dev))
printk("OP op=%4x, count=%4x\n", operation.mt_op, printk("OP op=%4x, count=%4x\n", operation.mt_op, operation.mt_count);
operation.mt_count);
}
if (operation.mt_count < 0) { if (operation.mt_count < 0)
tpqputs(TPQD_ALWAYS, tpqputs(TPQD_ALWAYS, "Warning: negative mt_count ignored");
"Warning: negative mt_count ignored");
}
ioctl_status.mt_resid = operation.mt_count; ioctl_status.mt_resid = operation.mt_count;
if (operation.mt_op == MTSEEK) { if (operation.mt_op == MTSEEK) {
if (!TP_HAVE_SEEK) { if (!TP_HAVE_SEEK)
return -ENOTTY; return -ENOTTY;
}
seek_addr_buf[0] = seek_addr_buf[0] = (operation.mt_count >> 16) & 0xff;
(operation.mt_count >> 16) & 0xff; seek_addr_buf[1] = (operation.mt_count >> 8) & 0xff;
seek_addr_buf[1] =
(operation.mt_count >> 8) & 0xff;
seek_addr_buf[2] = (operation.mt_count) & 0xff; seek_addr_buf[2] = (operation.mt_count) & 0xff;
if (operation.mt_count >> 24) { if (operation.mt_count >> 24)
return -EINVAL; return -EINVAL;
}
if ((error = do_ioctl_cmd(operation.mt_op)) != 0) { if ((error = do_ioctl_cmd(operation.mt_op)) != 0)
return error; return error;
}
ioctl_status.mt_resid = 0; ioctl_status.mt_resid = 0;
} else { } else {
while (operation.mt_count > 0) { while (operation.mt_count > 0) {
operation.mt_count--; operation.mt_count--;
if ((error = if ((error = do_ioctl_cmd(operation.mt_op)) != 0)
do_ioctl_cmd(operation.mt_op)) != 0) {
return error; return error;
}
ioctl_status.mt_resid = operation.mt_count; ioctl_status.mt_resid = operation.mt_count;
} }
...@@ -2648,9 +2490,8 @@ static int qic02_tape_ioctl(struct inode *inode, struct file *filp, ...@@ -2648,9 +2490,8 @@ static int qic02_tape_ioctl(struct inode *inode, struct file *filp,
return 0; return 0;
} else if (c == _IOC_NR(MTIOCGET)) { } else if (c == _IOC_NR(MTIOCGET)) {
if (TP_DIAGS(current_tape_dev)) { if (TP_DIAGS(current_tape_dev))
printk("GET "); printk("GET ");
}
CHECK_IOC_SIZE(mtget); CHECK_IOC_SIZE(mtget);
...@@ -2660,55 +2501,75 @@ static int qic02_tape_ioctl(struct inode *inode, struct file *filp, ...@@ -2660,55 +2501,75 @@ static int qic02_tape_ioctl(struct inode *inode, struct file *filp,
*/ */
/* copy results to user space */ /* copy results to user space */
if (copy_to_user if (copy_to_user((char *) ioarg, (char *) &ioctl_status, sizeof(ioctl_status)))
((char *) ioarg, (char *) &ioctl_status,
sizeof(ioctl_status))) {
return -EFAULT; return -EFAULT;
}
return 0; return 0;
} else if (TP_HAVE_TELL && (c == _IOC_NR(MTIOCPOS))) { } else if (TP_HAVE_TELL && (c == _IOC_NR(MTIOCPOS))) {
if (TP_DIAGS(current_tape_dev)) { if (TP_DIAGS(current_tape_dev))
printk("POS "); printk("POS ");
}
CHECK_IOC_SIZE(mtpos); CHECK_IOC_SIZE(mtpos);
tpqputs(TPQD_IOCTLS, "MTTELL reading block address"); tpqputs(TPQD_IOCTLS, "MTTELL reading block address");
if ((doing_read == YES) || (doing_write == YES)) { if (doing_read == YES || doing_write == YES)
finish_rw(AR_QCMDV_TELL_BLK); finish_rw(AR_QCMDV_TELL_BLK);
}
c = rdstatus((char *) blk_addr, sizeof(blk_addr), c = rdstatus((char *) blk_addr, sizeof(blk_addr), AR_QCMDV_TELL_BLK);
AR_QCMDV_TELL_BLK); if (c != TE_OK)
if (c != TE_OK) {
return -EIO; return -EIO;
}
ioctl_tell.mt_blkno = ioctl_tell.mt_blkno = (blk_addr[3] << 16) | (blk_addr[4] << 8) | blk_addr[5];
(blk_addr[3] << 16) | (blk_addr[4] << 8) | blk_addr[5];
/* copy results to user space */ /* copy results to user space */
if (copy_to_user if (copy_to_user((char *) ioarg, (char *) &ioctl_tell, sizeof(ioctl_tell)))
((char *) ioarg, (char *) &ioctl_tell,
sizeof(ioctl_tell))) {
return -EFAULT; return -EFAULT;
}
return 0; return 0;
} else { } else
return -ENOTTY; /* Other cmds not supported. */ return -ENOTTY; /* Other cmds not supported. */
}
} /* qic02_tape_ioctl */ } /* qic02_tape_ioctl */
static ssize_t qic02_do_tape_read(struct file *filp, char *buf, size_t count, loff_t * ppos)
{
int err;
down(&tape_op);
err = qic02_tape_read(filp, buf, count, ppos);
up(&tape_op);
return err;
}
static ssize_t qic02_do_tape_write(struct file *filp, const char *buf, size_t count, loff_t * ppos)
{
int err;
down(&tape_op);
err = qic02_tape_write(filp, buf, count, ppos);
up(&tape_op);
return err;
}
static int qic02_do_tape_ioctl(struct inode *inode, struct file *filp, unsigned int iocmd, unsigned long ioarg)
{
int err;
down(&tape_op);
err = qic02_tape_ioctl(inode, filp, iocmd, ioarg);
up(&tape_op);
return err;
}
/* These are (most) of the interface functions: */ /* These are (most) of the interface functions: */
static struct file_operations qic02_tape_fops = { static struct file_operations qic02_tape_fops = {
owner:THIS_MODULE, owner:THIS_MODULE,
llseek:no_llseek, llseek:no_llseek,
read:qic02_tape_read, read:qic02_do_tape_read,
write:qic02_tape_write, write:qic02_do_tape_write,
ioctl:qic02_tape_ioctl, ioctl:qic02_do_tape_ioctl,
open:qic02_tape_open, open:qic02_tape_open,
release:qic02_tape_release, release:qic02_tape_release,
}; };
...@@ -2719,10 +2580,8 @@ static void qic02_release_resources(void) ...@@ -2719,10 +2580,8 @@ static void qic02_release_resources(void)
free_irq(QIC02_TAPE_IRQ, NULL); free_irq(QIC02_TAPE_IRQ, NULL);
free_dma(QIC02_TAPE_DMA); free_dma(QIC02_TAPE_DMA);
release_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE); release_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE);
if (buffaddr) { if (buffaddr)
free_pages((unsigned long) buffaddr, free_pages((unsigned long) buffaddr, get_order(TPQBUF_SIZE));
get_order(TPQBUF_SIZE));
}
buffaddr = 0; /* Better to cause a panic than overwite someone else */ buffaddr = 0; /* Better to cause a panic than overwite someone else */
status_zombie = YES; status_zombie = YES;
} /* qic02_release_resources */ } /* qic02_release_resources */
...@@ -2733,49 +2592,35 @@ static int qic02_get_resources(void) ...@@ -2733,49 +2592,35 @@ static int qic02_get_resources(void)
/* First perform some checks. If one of them fails, /* First perform some checks. If one of them fails,
* the tape driver will not be registered to the system. * the tape driver will not be registered to the system.
*/ */
if (QIC02_TAPE_IRQ > 16) {
tpqputs(TPQD_ALWAYS, "Bogus interrupt number.");
return -ENXIO;
}
/* for DYNCONF, allocating IO, DMA and IRQ should not be done until /* for DYNCONF, allocating IO, DMA and IRQ should not be done until
* the config parameters have been set using MTSETCONFIG. * the config parameters have been set using MTSETCONFIG.
*/ */
/* Grab the IO region. */ /* Grab the IO region. */
if (!request_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE, if (!request_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE, TPQIC02_NAME)) {
TPQIC02_NAME)) { printk(TPQIC02_NAME ": IO space at 0x%x [%d ports] already reserved\n",
printk(TPQIC02_NAME
": IO space at 0x%x [%d ports] already reserved\n",
QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE); QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE);
return -ENXIO; return -ENXIO;
} }
/* get IRQ */ /* get IRQ */
if (request_irq if (request_irq(QIC02_TAPE_IRQ, qic02_tape_interrupt, SA_INTERRUPT, "QIC-02", NULL)) {
(QIC02_TAPE_IRQ, qic02_tape_interrupt, SA_INTERRUPT, "QIC-02", printk(TPQIC02_NAME ": can't allocate IRQ%d for QIC-02 tape\n", QIC02_TAPE_IRQ);
NULL)) {
printk(TPQIC02_NAME
": can't allocate IRQ%d for QIC-02 tape\n",
QIC02_TAPE_IRQ);
release_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE); release_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE);
return -EBUSY; return -EBUSY;
} }
/* After IRQ, allocate DMA channel */ /* After IRQ, allocate DMA channel */
if (request_dma(QIC02_TAPE_DMA, "QIC-02")) { if (request_dma(QIC02_TAPE_DMA, "QIC-02")) {
printk(TPQIC02_NAME printk(TPQIC02_NAME ": can't allocate DMA%d for QIC-02 tape\n", QIC02_TAPE_DMA);
": can't allocate DMA%d for QIC-02 tape\n",
QIC02_TAPE_DMA);
free_irq(QIC02_TAPE_IRQ, NULL); free_irq(QIC02_TAPE_IRQ, NULL);
release_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE); release_region(QIC02_TAPE_PORT, QIC02_TAPE_PORT_RANGE);
return -EBUSY; return -EBUSY;
} }
/* Setup the page-address for the dma transfer. */ /* Setup the page-address for the dma transfer. */
buffaddr = buffaddr = (void *) __get_dma_pages(GFP_KERNEL, get_order(TPQBUF_SIZE));
(void *) __get_dma_pages(GFP_KERNEL, get_order(TPQBUF_SIZE));
if (!buffaddr) { if (!buffaddr) {
qic02_release_resources(); qic02_release_resources();
return -EBUSY; /* Not ideal, EAGAIN perhaps? */ return -EBUSY; /* Not ideal, EAGAIN perhaps? */
...@@ -2783,8 +2628,7 @@ static int qic02_get_resources(void) ...@@ -2783,8 +2628,7 @@ static int qic02_get_resources(void)
memset(buffaddr, 0, TPQBUF_SIZE); memset(buffaddr, 0, TPQBUF_SIZE);
printk(TPQIC02_NAME printk(TPQIC02_NAME ": Settings: IRQ %d, DMA %d, IO 0x%x, IFC %s\n",
": Settings: IRQ %d, DMA %d, IO 0x%x, IFC %s\n",
QIC02_TAPE_IRQ, QIC02_TAPE_DMA, ((QIC02_TAPE_IFC == ARCHIVE) QIC02_TAPE_IRQ, QIC02_TAPE_DMA, ((QIC02_TAPE_IFC == ARCHIVE)
|| (QIC02_TAPE_IFC == || (QIC02_TAPE_IFC ==
MOUNTAIN)) ? MOUNTAIN)) ?
...@@ -2794,11 +2638,9 @@ static int qic02_get_resources(void) ...@@ -2794,11 +2638,9 @@ static int qic02_get_resources(void)
ARCHIVE) ? "Archive" : ARCHIVE) ? "Archive" :
"Wangtek")); "Wangtek"));
if (tape_reset(0) != TE_OK if (tape_reset(0) != TE_OK || tp_sense(TP_WRP | TP_POR | TP_CNI) != TE_OK) {
|| tp_sense(TP_WRP | TP_POR | TP_CNI) != TE_OK) {
/* No drive detected, so vanish */ /* No drive detected, so vanish */
tpqputs(TPQD_ALWAYS, tpqputs(TPQD_ALWAYS, "No drive detected -- releasing IO/IRQ/DMA.");
"No drive detected -- releasing IO/IRQ/DMA.");
status_dead = YES; status_dead = YES;
qic02_release_resources(); qic02_release_resources();
return -EIO; return -EIO;
...@@ -2812,13 +2654,11 @@ static int qic02_get_resources(void) ...@@ -2812,13 +2654,11 @@ static int qic02_get_resources(void)
int __init qic02_tape_init(void) int __init qic02_tape_init(void)
{ {
if (TPSTATSIZE != 6) { if (TPSTATSIZE != 6) {
printk(TPQIC02_NAME printk(TPQIC02_NAME ": internal error: tpstatus struct incorrect!\n");
": internal error: tpstatus struct incorrect!\n");
return -ENODEV; return -ENODEV;
} }
if ((TPQBUF_SIZE < 512) || (TPQBUF_SIZE >= 0x10000)) { if ((TPQBUF_SIZE < 512) || (TPQBUF_SIZE >= 0x10000)) {
printk(TPQIC02_NAME printk(TPQIC02_NAME ": internal error: DMA buffer size out of range\n");
": internal error: DMA buffer size out of range\n");
return -ENODEV; return -ENODEV;
} }
...@@ -2837,19 +2677,16 @@ int __init qic02_tape_init(void) ...@@ -2837,19 +2677,16 @@ int __init qic02_tape_init(void)
# error # error
# endif # endif
rcs_revision, rcs_date); rcs_revision, rcs_date);
if (qic02_get_resources()) { if (qic02_get_resources())
return -ENODEV; return -ENODEV;
}
#else #else
printk(TPQIC02_NAME ": Runtime config, %s, %s\n", printk(TPQIC02_NAME ": Runtime config, %s, %s\n", rcs_revision, rcs_date);
rcs_revision, rcs_date);
#endif #endif
printk(TPQIC02_NAME ": DMA buffers: %u blocks\n", NR_BLK_BUF); printk(TPQIC02_NAME ": DMA buffers: %u blocks\n", NR_BLK_BUF);
/* If we got this far, install driver functions */ /* If we got this far, install driver functions */
if (register_chrdev if (register_chrdev(QIC02_TAPE_MAJOR, TPQIC02_NAME, &qic02_tape_fops))
(QIC02_TAPE_MAJOR, TPQIC02_NAME, &qic02_tape_fops)) { {
printk(TPQIC02_NAME ": Unable to get chrdev major %d\n", printk(TPQIC02_NAME ": Unable to get chrdev major %d\n", QIC02_TAPE_MAJOR);
QIC02_TAPE_MAJOR);
#ifndef CONFIG_QIC02_DYNCONF #ifndef CONFIG_QIC02_DYNCONF
qic02_release_resources(); qic02_release_resources();
#endif #endif
...@@ -2894,11 +2731,9 @@ int __init qic02_tape_init(void) ...@@ -2894,11 +2731,9 @@ int __init qic02_tape_init(void)
tp_timer.function = qic02_tape_times_out; tp_timer.function = qic02_tape_times_out;
#ifndef CONFIG_QIC02_DYNCONF #ifndef CONFIG_QIC02_DYNCONF
if (tape_reset(0) != TE_OK if (tape_reset(0) != TE_OK || tp_sense(TP_WRP | TP_POR | TP_CNI) != TE_OK) {
|| tp_sense(TP_WRP | TP_POR | TP_CNI) != TE_OK) {
/* No drive detected, so vanish */ /* No drive detected, so vanish */
tpqputs(TPQD_ALWAYS, tpqputs(TPQD_ALWAYS, "No drive detected -- driver going on vacation...");
"No drive detected -- driver going on vacation...");
qic02_release_resources(); qic02_release_resources();
status_dead = YES; status_dead = YES;
return -ENODEV; return -ENODEV;
...@@ -2927,10 +2762,10 @@ int __init qic02_tape_init(void) ...@@ -2927,10 +2762,10 @@ int __init qic02_tape_init(void)
void cleanup_module(void) void cleanup_module(void)
{ {
if (status_zombie == NO) {
qic02_release_resources();
}
unregister_chrdev(QIC02_TAPE_MAJOR, TPQIC02_NAME); unregister_chrdev(QIC02_TAPE_MAJOR, TPQIC02_NAME);
if (status_zombie == NO)
qic02_release_resources();
devfs_find_and_unregister(NULL, "ntpqic11", QIC02_TAPE_MAJOR, 2, devfs_find_and_unregister(NULL, "ntpqic11", QIC02_TAPE_MAJOR, 2,
DEVFS_SPECIAL_CHR, 0); DEVFS_SPECIAL_CHR, 0);
devfs_find_and_unregister(NULL, "tpqic11", QIC02_TAPE_MAJOR, 3, devfs_find_and_unregister(NULL, "tpqic11", QIC02_TAPE_MAJOR, 3,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment