1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun pt.c (c) 1998 Grant R. Guenther <grant@torque.net>
3*4882a593Smuzhiyun Under the terms of the GNU General Public License.
4*4882a593Smuzhiyun
5*4882a593Smuzhiyun This is the high-level driver for parallel port ATAPI tape
6*4882a593Smuzhiyun drives based on chips supported by the paride module.
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun The driver implements both rewinding and non-rewinding
9*4882a593Smuzhiyun devices, filemarks, and the rewind ioctl. It allocates
10*4882a593Smuzhiyun a small internal "bounce buffer" for each open device, but
11*4882a593Smuzhiyun otherwise expects buffering and blocking to be done at the
12*4882a593Smuzhiyun user level. As with most block-structured tapes, short
13*4882a593Smuzhiyun writes are padded to full tape blocks, so reading back a file
14*4882a593Smuzhiyun may return more data than was actually written.
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun By default, the driver will autoprobe for a single parallel
17*4882a593Smuzhiyun port ATAPI tape drive, but if their individual parameters are
18*4882a593Smuzhiyun specified, the driver can handle up to 4 drives.
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun The rewinding devices are named /dev/pt0, /dev/pt1, ...
21*4882a593Smuzhiyun while the non-rewinding devices are /dev/npt0, /dev/npt1, etc.
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun The behaviour of the pt driver can be altered by setting
24*4882a593Smuzhiyun some parameters from the insmod command line. The following
25*4882a593Smuzhiyun parameters are adjustable:
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun drive0 These four arguments can be arrays of
28*4882a593Smuzhiyun drive1 1-6 integers as follows:
29*4882a593Smuzhiyun drive2
30*4882a593Smuzhiyun drive3 <prt>,<pro>,<uni>,<mod>,<slv>,<dly>
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun Where,
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun <prt> is the base of the parallel port address for
35*4882a593Smuzhiyun the corresponding drive. (required)
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun <pro> is the protocol number for the adapter that
38*4882a593Smuzhiyun supports this drive. These numbers are
39*4882a593Smuzhiyun logged by 'paride' when the protocol modules
40*4882a593Smuzhiyun are initialised. (0 if not given)
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun <uni> for those adapters that support chained
43*4882a593Smuzhiyun devices, this is the unit selector for the
44*4882a593Smuzhiyun chain of devices on the given port. It should
45*4882a593Smuzhiyun be zero for devices that don't support chaining.
46*4882a593Smuzhiyun (0 if not given)
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun <mod> this can be -1 to choose the best mode, or one
49*4882a593Smuzhiyun of the mode numbers supported by the adapter.
50*4882a593Smuzhiyun (-1 if not given)
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun <slv> ATAPI devices can be jumpered to master or slave.
53*4882a593Smuzhiyun Set this to 0 to choose the master drive, 1 to
54*4882a593Smuzhiyun choose the slave, -1 (the default) to choose the
55*4882a593Smuzhiyun first drive found.
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun <dly> some parallel ports require the driver to
58*4882a593Smuzhiyun go more slowly. -1 sets a default value that
59*4882a593Smuzhiyun should work with the chosen protocol. Otherwise,
60*4882a593Smuzhiyun set this to a small integer, the larger it is
61*4882a593Smuzhiyun the slower the port i/o. In some cases, setting
62*4882a593Smuzhiyun this to zero will speed up the device. (default -1)
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun major You may use this parameter to override the
65*4882a593Smuzhiyun default major number (96) that this driver
66*4882a593Smuzhiyun will use. Be sure to change the device
67*4882a593Smuzhiyun name as well.
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun name This parameter is a character string that
70*4882a593Smuzhiyun contains the name the kernel will use for this
71*4882a593Smuzhiyun device (in /proc output, for instance).
72*4882a593Smuzhiyun (default "pt").
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun verbose This parameter controls the amount of logging
75*4882a593Smuzhiyun that the driver will do. Set it to 0 for
76*4882a593Smuzhiyun normal operation, 1 to see autoprobe progress
77*4882a593Smuzhiyun messages, or 2 to see additional debugging
78*4882a593Smuzhiyun output. (default 0)
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun If this driver is built into the kernel, you can use
81*4882a593Smuzhiyun the following command line parameters, with the same values
82*4882a593Smuzhiyun as the corresponding module parameters listed above:
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun pt.drive0
85*4882a593Smuzhiyun pt.drive1
86*4882a593Smuzhiyun pt.drive2
87*4882a593Smuzhiyun pt.drive3
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun In addition, you can use the parameter pt.disable to disable
90*4882a593Smuzhiyun the driver entirely.
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun */
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun /* Changes:
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun 1.01 GRG 1998.05.06 Round up transfer size, fix ready_wait,
97*4882a593Smuzhiyun loosed interpretation of ATAPI standard
98*4882a593Smuzhiyun for clearing error status.
99*4882a593Smuzhiyun Eliminate sti();
100*4882a593Smuzhiyun 1.02 GRG 1998.06.16 Eliminate an Ugh.
101*4882a593Smuzhiyun 1.03 GRG 1998.08.15 Adjusted PT_TMO, use HZ in loop timing,
102*4882a593Smuzhiyun extra debugging
103*4882a593Smuzhiyun 1.04 GRG 1998.09.24 Repair minor coding error, added jumbo support
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun */
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun #define PT_VERSION "1.04"
108*4882a593Smuzhiyun #define PT_MAJOR 96
109*4882a593Smuzhiyun #define PT_NAME "pt"
110*4882a593Smuzhiyun #define PT_UNITS 4
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun #include <linux/types.h>
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun /* Here are things one can override from the insmod command.
115*4882a593Smuzhiyun Most are autoprobed by paride unless set here. Verbose is on
116*4882a593Smuzhiyun by default.
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun */
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun static int verbose = 0;
121*4882a593Smuzhiyun static int major = PT_MAJOR;
122*4882a593Smuzhiyun static char *name = PT_NAME;
123*4882a593Smuzhiyun static int disable = 0;
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun static int drive0[6] = { 0, 0, 0, -1, -1, -1 };
126*4882a593Smuzhiyun static int drive1[6] = { 0, 0, 0, -1, -1, -1 };
127*4882a593Smuzhiyun static int drive2[6] = { 0, 0, 0, -1, -1, -1 };
128*4882a593Smuzhiyun static int drive3[6] = { 0, 0, 0, -1, -1, -1 };
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun static int (*drives[4])[6] = {&drive0, &drive1, &drive2, &drive3};
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun #define D_PRT 0
133*4882a593Smuzhiyun #define D_PRO 1
134*4882a593Smuzhiyun #define D_UNI 2
135*4882a593Smuzhiyun #define D_MOD 3
136*4882a593Smuzhiyun #define D_SLV 4
137*4882a593Smuzhiyun #define D_DLY 5
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun #define DU (*drives[unit])
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun /* end of parameters */
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun #include <linux/module.h>
144*4882a593Smuzhiyun #include <linux/init.h>
145*4882a593Smuzhiyun #include <linux/fs.h>
146*4882a593Smuzhiyun #include <linux/delay.h>
147*4882a593Smuzhiyun #include <linux/slab.h>
148*4882a593Smuzhiyun #include <linux/mtio.h>
149*4882a593Smuzhiyun #include <linux/device.h>
150*4882a593Smuzhiyun #include <linux/sched.h> /* current, TASK_*, schedule_timeout() */
151*4882a593Smuzhiyun #include <linux/mutex.h>
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun #include <linux/uaccess.h>
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun module_param(verbose, int, 0);
156*4882a593Smuzhiyun module_param(major, int, 0);
157*4882a593Smuzhiyun module_param(name, charp, 0);
158*4882a593Smuzhiyun module_param_array(drive0, int, NULL, 0);
159*4882a593Smuzhiyun module_param_array(drive1, int, NULL, 0);
160*4882a593Smuzhiyun module_param_array(drive2, int, NULL, 0);
161*4882a593Smuzhiyun module_param_array(drive3, int, NULL, 0);
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun #include "paride.h"
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun #define PT_MAX_RETRIES 5
166*4882a593Smuzhiyun #define PT_TMO 3000 /* interrupt timeout in jiffies */
167*4882a593Smuzhiyun #define PT_SPIN_DEL 50 /* spin delay in micro-seconds */
168*4882a593Smuzhiyun #define PT_RESET_TMO 30 /* 30 seconds */
169*4882a593Smuzhiyun #define PT_READY_TMO 60 /* 60 seconds */
170*4882a593Smuzhiyun #define PT_REWIND_TMO 1200 /* 20 minutes */
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun #define PT_SPIN ((1000000/(HZ*PT_SPIN_DEL))*PT_TMO)
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun #define STAT_ERR 0x00001
175*4882a593Smuzhiyun #define STAT_INDEX 0x00002
176*4882a593Smuzhiyun #define STAT_ECC 0x00004
177*4882a593Smuzhiyun #define STAT_DRQ 0x00008
178*4882a593Smuzhiyun #define STAT_SEEK 0x00010
179*4882a593Smuzhiyun #define STAT_WRERR 0x00020
180*4882a593Smuzhiyun #define STAT_READY 0x00040
181*4882a593Smuzhiyun #define STAT_BUSY 0x00080
182*4882a593Smuzhiyun #define STAT_SENSE 0x1f000
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun #define ATAPI_TEST_READY 0x00
185*4882a593Smuzhiyun #define ATAPI_REWIND 0x01
186*4882a593Smuzhiyun #define ATAPI_REQ_SENSE 0x03
187*4882a593Smuzhiyun #define ATAPI_READ_6 0x08
188*4882a593Smuzhiyun #define ATAPI_WRITE_6 0x0a
189*4882a593Smuzhiyun #define ATAPI_WFM 0x10
190*4882a593Smuzhiyun #define ATAPI_IDENTIFY 0x12
191*4882a593Smuzhiyun #define ATAPI_MODE_SENSE 0x1a
192*4882a593Smuzhiyun #define ATAPI_LOG_SENSE 0x4d
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun static DEFINE_MUTEX(pt_mutex);
195*4882a593Smuzhiyun static int pt_open(struct inode *inode, struct file *file);
196*4882a593Smuzhiyun static long pt_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
197*4882a593Smuzhiyun static int pt_release(struct inode *inode, struct file *file);
198*4882a593Smuzhiyun static ssize_t pt_read(struct file *filp, char __user *buf,
199*4882a593Smuzhiyun size_t count, loff_t * ppos);
200*4882a593Smuzhiyun static ssize_t pt_write(struct file *filp, const char __user *buf,
201*4882a593Smuzhiyun size_t count, loff_t * ppos);
202*4882a593Smuzhiyun static int pt_detect(void);
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun /* bits in tape->flags */
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun #define PT_MEDIA 1
207*4882a593Smuzhiyun #define PT_WRITE_OK 2
208*4882a593Smuzhiyun #define PT_REWIND 4
209*4882a593Smuzhiyun #define PT_WRITING 8
210*4882a593Smuzhiyun #define PT_READING 16
211*4882a593Smuzhiyun #define PT_EOF 32
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun #define PT_NAMELEN 8
214*4882a593Smuzhiyun #define PT_BUFSIZE 16384
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun struct pt_unit {
217*4882a593Smuzhiyun struct pi_adapter pia; /* interface to paride layer */
218*4882a593Smuzhiyun struct pi_adapter *pi;
219*4882a593Smuzhiyun int flags; /* various state flags */
220*4882a593Smuzhiyun int last_sense; /* result of last request sense */
221*4882a593Smuzhiyun int drive; /* drive */
222*4882a593Smuzhiyun atomic_t available; /* 1 if access is available 0 otherwise */
223*4882a593Smuzhiyun int bs; /* block size */
224*4882a593Smuzhiyun int capacity; /* Size of tape in KB */
225*4882a593Smuzhiyun int present; /* device present ? */
226*4882a593Smuzhiyun char *bufptr;
227*4882a593Smuzhiyun char name[PT_NAMELEN]; /* pf0, pf1, ... */
228*4882a593Smuzhiyun };
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun static int pt_identify(struct pt_unit *tape);
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun static struct pt_unit pt[PT_UNITS];
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun static char pt_scratch[512]; /* scratch block buffer */
235*4882a593Smuzhiyun static void *par_drv; /* reference of parport driver */
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun /* kernel glue structures */
238*4882a593Smuzhiyun
239*4882a593Smuzhiyun static const struct file_operations pt_fops = {
240*4882a593Smuzhiyun .owner = THIS_MODULE,
241*4882a593Smuzhiyun .read = pt_read,
242*4882a593Smuzhiyun .write = pt_write,
243*4882a593Smuzhiyun .unlocked_ioctl = pt_ioctl,
244*4882a593Smuzhiyun .open = pt_open,
245*4882a593Smuzhiyun .release = pt_release,
246*4882a593Smuzhiyun .llseek = noop_llseek,
247*4882a593Smuzhiyun };
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun /* sysfs class support */
250*4882a593Smuzhiyun static struct class *pt_class;
251*4882a593Smuzhiyun
status_reg(struct pi_adapter * pi)252*4882a593Smuzhiyun static inline int status_reg(struct pi_adapter *pi)
253*4882a593Smuzhiyun {
254*4882a593Smuzhiyun return pi_read_regr(pi, 1, 6);
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun
read_reg(struct pi_adapter * pi,int reg)257*4882a593Smuzhiyun static inline int read_reg(struct pi_adapter *pi, int reg)
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun return pi_read_regr(pi, 0, reg);
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun
write_reg(struct pi_adapter * pi,int reg,int val)262*4882a593Smuzhiyun static inline void write_reg(struct pi_adapter *pi, int reg, int val)
263*4882a593Smuzhiyun {
264*4882a593Smuzhiyun pi_write_regr(pi, 0, reg, val);
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun
DRIVE(struct pt_unit * tape)267*4882a593Smuzhiyun static inline u8 DRIVE(struct pt_unit *tape)
268*4882a593Smuzhiyun {
269*4882a593Smuzhiyun return 0xa0+0x10*tape->drive;
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun
pt_wait(struct pt_unit * tape,int go,int stop,char * fun,char * msg)272*4882a593Smuzhiyun static int pt_wait(struct pt_unit *tape, int go, int stop, char *fun, char *msg)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun int j, r, e, s, p;
275*4882a593Smuzhiyun struct pi_adapter *pi = tape->pi;
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun j = 0;
278*4882a593Smuzhiyun while ((((r = status_reg(pi)) & go) || (stop && (!(r & stop))))
279*4882a593Smuzhiyun && (j++ < PT_SPIN))
280*4882a593Smuzhiyun udelay(PT_SPIN_DEL);
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun if ((r & (STAT_ERR & stop)) || (j > PT_SPIN)) {
283*4882a593Smuzhiyun s = read_reg(pi, 7);
284*4882a593Smuzhiyun e = read_reg(pi, 1);
285*4882a593Smuzhiyun p = read_reg(pi, 2);
286*4882a593Smuzhiyun if (j > PT_SPIN)
287*4882a593Smuzhiyun e |= 0x100;
288*4882a593Smuzhiyun if (fun)
289*4882a593Smuzhiyun printk("%s: %s %s: alt=0x%x stat=0x%x err=0x%x"
290*4882a593Smuzhiyun " loop=%d phase=%d\n",
291*4882a593Smuzhiyun tape->name, fun, msg, r, s, e, j, p);
292*4882a593Smuzhiyun return (e << 8) + s;
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun return 0;
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun
pt_command(struct pt_unit * tape,char * cmd,int dlen,char * fun)297*4882a593Smuzhiyun static int pt_command(struct pt_unit *tape, char *cmd, int dlen, char *fun)
298*4882a593Smuzhiyun {
299*4882a593Smuzhiyun struct pi_adapter *pi = tape->pi;
300*4882a593Smuzhiyun pi_connect(pi);
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun write_reg(pi, 6, DRIVE(tape));
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun if (pt_wait(tape, STAT_BUSY | STAT_DRQ, 0, fun, "before command")) {
305*4882a593Smuzhiyun pi_disconnect(pi);
306*4882a593Smuzhiyun return -1;
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun write_reg(pi, 4, dlen % 256);
310*4882a593Smuzhiyun write_reg(pi, 5, dlen / 256);
311*4882a593Smuzhiyun write_reg(pi, 7, 0xa0); /* ATAPI packet command */
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun if (pt_wait(tape, STAT_BUSY, STAT_DRQ, fun, "command DRQ")) {
314*4882a593Smuzhiyun pi_disconnect(pi);
315*4882a593Smuzhiyun return -1;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun if (read_reg(pi, 2) != 1) {
319*4882a593Smuzhiyun printk("%s: %s: command phase error\n", tape->name, fun);
320*4882a593Smuzhiyun pi_disconnect(pi);
321*4882a593Smuzhiyun return -1;
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun pi_write_block(pi, cmd, 12);
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun return 0;
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun
pt_completion(struct pt_unit * tape,char * buf,char * fun)329*4882a593Smuzhiyun static int pt_completion(struct pt_unit *tape, char *buf, char *fun)
330*4882a593Smuzhiyun {
331*4882a593Smuzhiyun struct pi_adapter *pi = tape->pi;
332*4882a593Smuzhiyun int r, s, n, p;
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun r = pt_wait(tape, STAT_BUSY, STAT_DRQ | STAT_READY | STAT_ERR,
335*4882a593Smuzhiyun fun, "completion");
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun if (read_reg(pi, 7) & STAT_DRQ) {
338*4882a593Smuzhiyun n = (((read_reg(pi, 4) + 256 * read_reg(pi, 5)) +
339*4882a593Smuzhiyun 3) & 0xfffc);
340*4882a593Smuzhiyun p = read_reg(pi, 2) & 3;
341*4882a593Smuzhiyun if (p == 0)
342*4882a593Smuzhiyun pi_write_block(pi, buf, n);
343*4882a593Smuzhiyun if (p == 2)
344*4882a593Smuzhiyun pi_read_block(pi, buf, n);
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun s = pt_wait(tape, STAT_BUSY, STAT_READY | STAT_ERR, fun, "data done");
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun pi_disconnect(pi);
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun return (r ? r : s);
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun
pt_req_sense(struct pt_unit * tape,int quiet)354*4882a593Smuzhiyun static void pt_req_sense(struct pt_unit *tape, int quiet)
355*4882a593Smuzhiyun {
356*4882a593Smuzhiyun char rs_cmd[12] = { ATAPI_REQ_SENSE, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0 };
357*4882a593Smuzhiyun char buf[16];
358*4882a593Smuzhiyun int r;
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun r = pt_command(tape, rs_cmd, 16, "Request sense");
361*4882a593Smuzhiyun mdelay(1);
362*4882a593Smuzhiyun if (!r)
363*4882a593Smuzhiyun pt_completion(tape, buf, "Request sense");
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun tape->last_sense = -1;
366*4882a593Smuzhiyun if (!r) {
367*4882a593Smuzhiyun if (!quiet)
368*4882a593Smuzhiyun printk("%s: Sense key: %x, ASC: %x, ASQ: %x\n",
369*4882a593Smuzhiyun tape->name, buf[2] & 0xf, buf[12], buf[13]);
370*4882a593Smuzhiyun tape->last_sense = (buf[2] & 0xf) | ((buf[12] & 0xff) << 8)
371*4882a593Smuzhiyun | ((buf[13] & 0xff) << 16);
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun
pt_atapi(struct pt_unit * tape,char * cmd,int dlen,char * buf,char * fun)375*4882a593Smuzhiyun static int pt_atapi(struct pt_unit *tape, char *cmd, int dlen, char *buf, char *fun)
376*4882a593Smuzhiyun {
377*4882a593Smuzhiyun int r;
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun r = pt_command(tape, cmd, dlen, fun);
380*4882a593Smuzhiyun mdelay(1);
381*4882a593Smuzhiyun if (!r)
382*4882a593Smuzhiyun r = pt_completion(tape, buf, fun);
383*4882a593Smuzhiyun if (r)
384*4882a593Smuzhiyun pt_req_sense(tape, !fun);
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun return r;
387*4882a593Smuzhiyun }
388*4882a593Smuzhiyun
pt_sleep(int cs)389*4882a593Smuzhiyun static void pt_sleep(int cs)
390*4882a593Smuzhiyun {
391*4882a593Smuzhiyun schedule_timeout_interruptible(cs);
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun
pt_poll_dsc(struct pt_unit * tape,int pause,int tmo,char * msg)394*4882a593Smuzhiyun static int pt_poll_dsc(struct pt_unit *tape, int pause, int tmo, char *msg)
395*4882a593Smuzhiyun {
396*4882a593Smuzhiyun struct pi_adapter *pi = tape->pi;
397*4882a593Smuzhiyun int k, e, s;
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun k = 0;
400*4882a593Smuzhiyun e = 0;
401*4882a593Smuzhiyun s = 0;
402*4882a593Smuzhiyun while (k < tmo) {
403*4882a593Smuzhiyun pt_sleep(pause);
404*4882a593Smuzhiyun k++;
405*4882a593Smuzhiyun pi_connect(pi);
406*4882a593Smuzhiyun write_reg(pi, 6, DRIVE(tape));
407*4882a593Smuzhiyun s = read_reg(pi, 7);
408*4882a593Smuzhiyun e = read_reg(pi, 1);
409*4882a593Smuzhiyun pi_disconnect(pi);
410*4882a593Smuzhiyun if (s & (STAT_ERR | STAT_SEEK))
411*4882a593Smuzhiyun break;
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun if ((k >= tmo) || (s & STAT_ERR)) {
414*4882a593Smuzhiyun if (k >= tmo)
415*4882a593Smuzhiyun printk("%s: %s DSC timeout\n", tape->name, msg);
416*4882a593Smuzhiyun else
417*4882a593Smuzhiyun printk("%s: %s stat=0x%x err=0x%x\n", tape->name, msg, s,
418*4882a593Smuzhiyun e);
419*4882a593Smuzhiyun pt_req_sense(tape, 0);
420*4882a593Smuzhiyun return 0;
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun return 1;
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun
pt_media_access_cmd(struct pt_unit * tape,int tmo,char * cmd,char * fun)425*4882a593Smuzhiyun static void pt_media_access_cmd(struct pt_unit *tape, int tmo, char *cmd, char *fun)
426*4882a593Smuzhiyun {
427*4882a593Smuzhiyun if (pt_command(tape, cmd, 0, fun)) {
428*4882a593Smuzhiyun pt_req_sense(tape, 0);
429*4882a593Smuzhiyun return;
430*4882a593Smuzhiyun }
431*4882a593Smuzhiyun pi_disconnect(tape->pi);
432*4882a593Smuzhiyun pt_poll_dsc(tape, HZ, tmo, fun);
433*4882a593Smuzhiyun }
434*4882a593Smuzhiyun
pt_rewind(struct pt_unit * tape)435*4882a593Smuzhiyun static void pt_rewind(struct pt_unit *tape)
436*4882a593Smuzhiyun {
437*4882a593Smuzhiyun char rw_cmd[12] = { ATAPI_REWIND, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun pt_media_access_cmd(tape, PT_REWIND_TMO, rw_cmd, "rewind");
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun
pt_write_fm(struct pt_unit * tape)442*4882a593Smuzhiyun static void pt_write_fm(struct pt_unit *tape)
443*4882a593Smuzhiyun {
444*4882a593Smuzhiyun char wm_cmd[12] = { ATAPI_WFM, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 };
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun pt_media_access_cmd(tape, PT_TMO, wm_cmd, "write filemark");
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun #define DBMSG(msg) ((verbose>1)?(msg):NULL)
450*4882a593Smuzhiyun
pt_reset(struct pt_unit * tape)451*4882a593Smuzhiyun static int pt_reset(struct pt_unit *tape)
452*4882a593Smuzhiyun {
453*4882a593Smuzhiyun struct pi_adapter *pi = tape->pi;
454*4882a593Smuzhiyun int i, k, flg;
455*4882a593Smuzhiyun int expect[5] = { 1, 1, 1, 0x14, 0xeb };
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun pi_connect(pi);
458*4882a593Smuzhiyun write_reg(pi, 6, DRIVE(tape));
459*4882a593Smuzhiyun write_reg(pi, 7, 8);
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun pt_sleep(20 * HZ / 1000);
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun k = 0;
464*4882a593Smuzhiyun while ((k++ < PT_RESET_TMO) && (status_reg(pi) & STAT_BUSY))
465*4882a593Smuzhiyun pt_sleep(HZ / 10);
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun flg = 1;
468*4882a593Smuzhiyun for (i = 0; i < 5; i++)
469*4882a593Smuzhiyun flg &= (read_reg(pi, i + 1) == expect[i]);
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun if (verbose) {
472*4882a593Smuzhiyun printk("%s: Reset (%d) signature = ", tape->name, k);
473*4882a593Smuzhiyun for (i = 0; i < 5; i++)
474*4882a593Smuzhiyun printk("%3x", read_reg(pi, i + 1));
475*4882a593Smuzhiyun if (!flg)
476*4882a593Smuzhiyun printk(" (incorrect)");
477*4882a593Smuzhiyun printk("\n");
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun pi_disconnect(pi);
481*4882a593Smuzhiyun return flg - 1;
482*4882a593Smuzhiyun }
483*4882a593Smuzhiyun
pt_ready_wait(struct pt_unit * tape,int tmo)484*4882a593Smuzhiyun static int pt_ready_wait(struct pt_unit *tape, int tmo)
485*4882a593Smuzhiyun {
486*4882a593Smuzhiyun char tr_cmd[12] = { ATAPI_TEST_READY, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
487*4882a593Smuzhiyun int k, p;
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun k = 0;
490*4882a593Smuzhiyun while (k < tmo) {
491*4882a593Smuzhiyun tape->last_sense = 0;
492*4882a593Smuzhiyun pt_atapi(tape, tr_cmd, 0, NULL, DBMSG("test unit ready"));
493*4882a593Smuzhiyun p = tape->last_sense;
494*4882a593Smuzhiyun if (!p)
495*4882a593Smuzhiyun return 0;
496*4882a593Smuzhiyun if (!(((p & 0xffff) == 0x0402) || ((p & 0xff) == 6)))
497*4882a593Smuzhiyun return p;
498*4882a593Smuzhiyun k++;
499*4882a593Smuzhiyun pt_sleep(HZ);
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun return 0x000020; /* timeout */
502*4882a593Smuzhiyun }
503*4882a593Smuzhiyun
xs(char * buf,char * targ,int offs,int len)504*4882a593Smuzhiyun static void xs(char *buf, char *targ, int offs, int len)
505*4882a593Smuzhiyun {
506*4882a593Smuzhiyun int j, k, l;
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun j = 0;
509*4882a593Smuzhiyun l = 0;
510*4882a593Smuzhiyun for (k = 0; k < len; k++)
511*4882a593Smuzhiyun if ((buf[k + offs] != 0x20) || (buf[k + offs] != l))
512*4882a593Smuzhiyun l = targ[j++] = buf[k + offs];
513*4882a593Smuzhiyun if (l == 0x20)
514*4882a593Smuzhiyun j--;
515*4882a593Smuzhiyun targ[j] = 0;
516*4882a593Smuzhiyun }
517*4882a593Smuzhiyun
xn(char * buf,int offs,int size)518*4882a593Smuzhiyun static int xn(char *buf, int offs, int size)
519*4882a593Smuzhiyun {
520*4882a593Smuzhiyun int v, k;
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun v = 0;
523*4882a593Smuzhiyun for (k = 0; k < size; k++)
524*4882a593Smuzhiyun v = v * 256 + (buf[k + offs] & 0xff);
525*4882a593Smuzhiyun return v;
526*4882a593Smuzhiyun }
527*4882a593Smuzhiyun
pt_identify(struct pt_unit * tape)528*4882a593Smuzhiyun static int pt_identify(struct pt_unit *tape)
529*4882a593Smuzhiyun {
530*4882a593Smuzhiyun int dt, s;
531*4882a593Smuzhiyun char *ms[2] = { "master", "slave" };
532*4882a593Smuzhiyun char mf[10], id[18];
533*4882a593Smuzhiyun char id_cmd[12] = { ATAPI_IDENTIFY, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0 };
534*4882a593Smuzhiyun char ms_cmd[12] =
535*4882a593Smuzhiyun { ATAPI_MODE_SENSE, 0, 0x2a, 0, 36, 0, 0, 0, 0, 0, 0, 0 };
536*4882a593Smuzhiyun char ls_cmd[12] =
537*4882a593Smuzhiyun { ATAPI_LOG_SENSE, 0, 0x71, 0, 0, 0, 0, 0, 36, 0, 0, 0 };
538*4882a593Smuzhiyun char buf[36];
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun s = pt_atapi(tape, id_cmd, 36, buf, "identify");
541*4882a593Smuzhiyun if (s)
542*4882a593Smuzhiyun return -1;
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun dt = buf[0] & 0x1f;
545*4882a593Smuzhiyun if (dt != 1) {
546*4882a593Smuzhiyun if (verbose)
547*4882a593Smuzhiyun printk("%s: Drive %d, unsupported type %d\n",
548*4882a593Smuzhiyun tape->name, tape->drive, dt);
549*4882a593Smuzhiyun return -1;
550*4882a593Smuzhiyun }
551*4882a593Smuzhiyun
552*4882a593Smuzhiyun xs(buf, mf, 8, 8);
553*4882a593Smuzhiyun xs(buf, id, 16, 16);
554*4882a593Smuzhiyun
555*4882a593Smuzhiyun tape->flags = 0;
556*4882a593Smuzhiyun tape->capacity = 0;
557*4882a593Smuzhiyun tape->bs = 0;
558*4882a593Smuzhiyun
559*4882a593Smuzhiyun if (!pt_ready_wait(tape, PT_READY_TMO))
560*4882a593Smuzhiyun tape->flags |= PT_MEDIA;
561*4882a593Smuzhiyun
562*4882a593Smuzhiyun if (!pt_atapi(tape, ms_cmd, 36, buf, "mode sense")) {
563*4882a593Smuzhiyun if (!(buf[2] & 0x80))
564*4882a593Smuzhiyun tape->flags |= PT_WRITE_OK;
565*4882a593Smuzhiyun tape->bs = xn(buf, 10, 2);
566*4882a593Smuzhiyun }
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun if (!pt_atapi(tape, ls_cmd, 36, buf, "log sense"))
569*4882a593Smuzhiyun tape->capacity = xn(buf, 24, 4);
570*4882a593Smuzhiyun
571*4882a593Smuzhiyun printk("%s: %s %s, %s", tape->name, mf, id, ms[tape->drive]);
572*4882a593Smuzhiyun if (!(tape->flags & PT_MEDIA))
573*4882a593Smuzhiyun printk(", no media\n");
574*4882a593Smuzhiyun else {
575*4882a593Smuzhiyun if (!(tape->flags & PT_WRITE_OK))
576*4882a593Smuzhiyun printk(", RO");
577*4882a593Smuzhiyun printk(", blocksize %d, %d MB\n", tape->bs, tape->capacity / 1024);
578*4882a593Smuzhiyun }
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun return 0;
581*4882a593Smuzhiyun }
582*4882a593Smuzhiyun
583*4882a593Smuzhiyun
584*4882a593Smuzhiyun /*
585*4882a593Smuzhiyun * returns 0, with id set if drive is detected
586*4882a593Smuzhiyun * -1, if drive detection failed
587*4882a593Smuzhiyun */
pt_probe(struct pt_unit * tape)588*4882a593Smuzhiyun static int pt_probe(struct pt_unit *tape)
589*4882a593Smuzhiyun {
590*4882a593Smuzhiyun if (tape->drive == -1) {
591*4882a593Smuzhiyun for (tape->drive = 0; tape->drive <= 1; tape->drive++)
592*4882a593Smuzhiyun if (!pt_reset(tape))
593*4882a593Smuzhiyun return pt_identify(tape);
594*4882a593Smuzhiyun } else {
595*4882a593Smuzhiyun if (!pt_reset(tape))
596*4882a593Smuzhiyun return pt_identify(tape);
597*4882a593Smuzhiyun }
598*4882a593Smuzhiyun return -1;
599*4882a593Smuzhiyun }
600*4882a593Smuzhiyun
pt_detect(void)601*4882a593Smuzhiyun static int pt_detect(void)
602*4882a593Smuzhiyun {
603*4882a593Smuzhiyun struct pt_unit *tape;
604*4882a593Smuzhiyun int specified = 0, found = 0;
605*4882a593Smuzhiyun int unit;
606*4882a593Smuzhiyun
607*4882a593Smuzhiyun printk("%s: %s version %s, major %d\n", name, name, PT_VERSION, major);
608*4882a593Smuzhiyun
609*4882a593Smuzhiyun par_drv = pi_register_driver(name);
610*4882a593Smuzhiyun if (!par_drv) {
611*4882a593Smuzhiyun pr_err("failed to register %s driver\n", name);
612*4882a593Smuzhiyun return -1;
613*4882a593Smuzhiyun }
614*4882a593Smuzhiyun
615*4882a593Smuzhiyun specified = 0;
616*4882a593Smuzhiyun for (unit = 0; unit < PT_UNITS; unit++) {
617*4882a593Smuzhiyun struct pt_unit *tape = &pt[unit];
618*4882a593Smuzhiyun tape->pi = &tape->pia;
619*4882a593Smuzhiyun atomic_set(&tape->available, 1);
620*4882a593Smuzhiyun tape->flags = 0;
621*4882a593Smuzhiyun tape->last_sense = 0;
622*4882a593Smuzhiyun tape->present = 0;
623*4882a593Smuzhiyun tape->bufptr = NULL;
624*4882a593Smuzhiyun tape->drive = DU[D_SLV];
625*4882a593Smuzhiyun snprintf(tape->name, PT_NAMELEN, "%s%d", name, unit);
626*4882a593Smuzhiyun if (!DU[D_PRT])
627*4882a593Smuzhiyun continue;
628*4882a593Smuzhiyun specified++;
629*4882a593Smuzhiyun if (pi_init(tape->pi, 0, DU[D_PRT], DU[D_MOD], DU[D_UNI],
630*4882a593Smuzhiyun DU[D_PRO], DU[D_DLY], pt_scratch, PI_PT,
631*4882a593Smuzhiyun verbose, tape->name)) {
632*4882a593Smuzhiyun if (!pt_probe(tape)) {
633*4882a593Smuzhiyun tape->present = 1;
634*4882a593Smuzhiyun found++;
635*4882a593Smuzhiyun } else
636*4882a593Smuzhiyun pi_release(tape->pi);
637*4882a593Smuzhiyun }
638*4882a593Smuzhiyun }
639*4882a593Smuzhiyun if (specified == 0) {
640*4882a593Smuzhiyun tape = pt;
641*4882a593Smuzhiyun if (pi_init(tape->pi, 1, -1, -1, -1, -1, -1, pt_scratch,
642*4882a593Smuzhiyun PI_PT, verbose, tape->name)) {
643*4882a593Smuzhiyun if (!pt_probe(tape)) {
644*4882a593Smuzhiyun tape->present = 1;
645*4882a593Smuzhiyun found++;
646*4882a593Smuzhiyun } else
647*4882a593Smuzhiyun pi_release(tape->pi);
648*4882a593Smuzhiyun }
649*4882a593Smuzhiyun
650*4882a593Smuzhiyun }
651*4882a593Smuzhiyun if (found)
652*4882a593Smuzhiyun return 0;
653*4882a593Smuzhiyun
654*4882a593Smuzhiyun pi_unregister_driver(par_drv);
655*4882a593Smuzhiyun printk("%s: No ATAPI tape drive detected\n", name);
656*4882a593Smuzhiyun return -1;
657*4882a593Smuzhiyun }
658*4882a593Smuzhiyun
pt_open(struct inode * inode,struct file * file)659*4882a593Smuzhiyun static int pt_open(struct inode *inode, struct file *file)
660*4882a593Smuzhiyun {
661*4882a593Smuzhiyun int unit = iminor(inode) & 0x7F;
662*4882a593Smuzhiyun struct pt_unit *tape = pt + unit;
663*4882a593Smuzhiyun int err;
664*4882a593Smuzhiyun
665*4882a593Smuzhiyun mutex_lock(&pt_mutex);
666*4882a593Smuzhiyun if (unit >= PT_UNITS || (!tape->present)) {
667*4882a593Smuzhiyun mutex_unlock(&pt_mutex);
668*4882a593Smuzhiyun return -ENODEV;
669*4882a593Smuzhiyun }
670*4882a593Smuzhiyun
671*4882a593Smuzhiyun err = -EBUSY;
672*4882a593Smuzhiyun if (!atomic_dec_and_test(&tape->available))
673*4882a593Smuzhiyun goto out;
674*4882a593Smuzhiyun
675*4882a593Smuzhiyun pt_identify(tape);
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun err = -ENODEV;
678*4882a593Smuzhiyun if (!(tape->flags & PT_MEDIA))
679*4882a593Smuzhiyun goto out;
680*4882a593Smuzhiyun
681*4882a593Smuzhiyun err = -EROFS;
682*4882a593Smuzhiyun if ((!(tape->flags & PT_WRITE_OK)) && (file->f_mode & FMODE_WRITE))
683*4882a593Smuzhiyun goto out;
684*4882a593Smuzhiyun
685*4882a593Smuzhiyun if (!(iminor(inode) & 128))
686*4882a593Smuzhiyun tape->flags |= PT_REWIND;
687*4882a593Smuzhiyun
688*4882a593Smuzhiyun err = -ENOMEM;
689*4882a593Smuzhiyun tape->bufptr = kmalloc(PT_BUFSIZE, GFP_KERNEL);
690*4882a593Smuzhiyun if (tape->bufptr == NULL) {
691*4882a593Smuzhiyun printk("%s: buffer allocation failed\n", tape->name);
692*4882a593Smuzhiyun goto out;
693*4882a593Smuzhiyun }
694*4882a593Smuzhiyun
695*4882a593Smuzhiyun file->private_data = tape;
696*4882a593Smuzhiyun mutex_unlock(&pt_mutex);
697*4882a593Smuzhiyun return 0;
698*4882a593Smuzhiyun
699*4882a593Smuzhiyun out:
700*4882a593Smuzhiyun atomic_inc(&tape->available);
701*4882a593Smuzhiyun mutex_unlock(&pt_mutex);
702*4882a593Smuzhiyun return err;
703*4882a593Smuzhiyun }
704*4882a593Smuzhiyun
pt_ioctl(struct file * file,unsigned int cmd,unsigned long arg)705*4882a593Smuzhiyun static long pt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
706*4882a593Smuzhiyun {
707*4882a593Smuzhiyun struct pt_unit *tape = file->private_data;
708*4882a593Smuzhiyun struct mtop __user *p = (void __user *)arg;
709*4882a593Smuzhiyun struct mtop mtop;
710*4882a593Smuzhiyun
711*4882a593Smuzhiyun switch (cmd) {
712*4882a593Smuzhiyun case MTIOCTOP:
713*4882a593Smuzhiyun if (copy_from_user(&mtop, p, sizeof(struct mtop)))
714*4882a593Smuzhiyun return -EFAULT;
715*4882a593Smuzhiyun
716*4882a593Smuzhiyun switch (mtop.mt_op) {
717*4882a593Smuzhiyun
718*4882a593Smuzhiyun case MTREW:
719*4882a593Smuzhiyun mutex_lock(&pt_mutex);
720*4882a593Smuzhiyun pt_rewind(tape);
721*4882a593Smuzhiyun mutex_unlock(&pt_mutex);
722*4882a593Smuzhiyun return 0;
723*4882a593Smuzhiyun
724*4882a593Smuzhiyun case MTWEOF:
725*4882a593Smuzhiyun mutex_lock(&pt_mutex);
726*4882a593Smuzhiyun pt_write_fm(tape);
727*4882a593Smuzhiyun mutex_unlock(&pt_mutex);
728*4882a593Smuzhiyun return 0;
729*4882a593Smuzhiyun
730*4882a593Smuzhiyun default:
731*4882a593Smuzhiyun /* FIXME: rate limit ?? */
732*4882a593Smuzhiyun printk(KERN_DEBUG "%s: Unimplemented mt_op %d\n", tape->name,
733*4882a593Smuzhiyun mtop.mt_op);
734*4882a593Smuzhiyun return -EINVAL;
735*4882a593Smuzhiyun }
736*4882a593Smuzhiyun
737*4882a593Smuzhiyun default:
738*4882a593Smuzhiyun return -ENOTTY;
739*4882a593Smuzhiyun }
740*4882a593Smuzhiyun }
741*4882a593Smuzhiyun
742*4882a593Smuzhiyun static int
pt_release(struct inode * inode,struct file * file)743*4882a593Smuzhiyun pt_release(struct inode *inode, struct file *file)
744*4882a593Smuzhiyun {
745*4882a593Smuzhiyun struct pt_unit *tape = file->private_data;
746*4882a593Smuzhiyun
747*4882a593Smuzhiyun if (atomic_read(&tape->available) > 1)
748*4882a593Smuzhiyun return -EINVAL;
749*4882a593Smuzhiyun
750*4882a593Smuzhiyun if (tape->flags & PT_WRITING)
751*4882a593Smuzhiyun pt_write_fm(tape);
752*4882a593Smuzhiyun
753*4882a593Smuzhiyun if (tape->flags & PT_REWIND)
754*4882a593Smuzhiyun pt_rewind(tape);
755*4882a593Smuzhiyun
756*4882a593Smuzhiyun kfree(tape->bufptr);
757*4882a593Smuzhiyun tape->bufptr = NULL;
758*4882a593Smuzhiyun
759*4882a593Smuzhiyun atomic_inc(&tape->available);
760*4882a593Smuzhiyun
761*4882a593Smuzhiyun return 0;
762*4882a593Smuzhiyun
763*4882a593Smuzhiyun }
764*4882a593Smuzhiyun
pt_read(struct file * filp,char __user * buf,size_t count,loff_t * ppos)765*4882a593Smuzhiyun static ssize_t pt_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
766*4882a593Smuzhiyun {
767*4882a593Smuzhiyun struct pt_unit *tape = filp->private_data;
768*4882a593Smuzhiyun struct pi_adapter *pi = tape->pi;
769*4882a593Smuzhiyun char rd_cmd[12] = { ATAPI_READ_6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
770*4882a593Smuzhiyun int k, n, r, p, s, t, b;
771*4882a593Smuzhiyun
772*4882a593Smuzhiyun if (!(tape->flags & (PT_READING | PT_WRITING))) {
773*4882a593Smuzhiyun tape->flags |= PT_READING;
774*4882a593Smuzhiyun if (pt_atapi(tape, rd_cmd, 0, NULL, "start read-ahead"))
775*4882a593Smuzhiyun return -EIO;
776*4882a593Smuzhiyun } else if (tape->flags & PT_WRITING)
777*4882a593Smuzhiyun return -EIO;
778*4882a593Smuzhiyun
779*4882a593Smuzhiyun if (tape->flags & PT_EOF)
780*4882a593Smuzhiyun return 0;
781*4882a593Smuzhiyun
782*4882a593Smuzhiyun t = 0;
783*4882a593Smuzhiyun
784*4882a593Smuzhiyun while (count > 0) {
785*4882a593Smuzhiyun
786*4882a593Smuzhiyun if (!pt_poll_dsc(tape, HZ / 100, PT_TMO, "read"))
787*4882a593Smuzhiyun return -EIO;
788*4882a593Smuzhiyun
789*4882a593Smuzhiyun n = count;
790*4882a593Smuzhiyun if (n > 32768)
791*4882a593Smuzhiyun n = 32768; /* max per command */
792*4882a593Smuzhiyun b = (n - 1 + tape->bs) / tape->bs;
793*4882a593Smuzhiyun n = b * tape->bs; /* rounded up to even block */
794*4882a593Smuzhiyun
795*4882a593Smuzhiyun rd_cmd[4] = b;
796*4882a593Smuzhiyun
797*4882a593Smuzhiyun r = pt_command(tape, rd_cmd, n, "read");
798*4882a593Smuzhiyun
799*4882a593Smuzhiyun mdelay(1);
800*4882a593Smuzhiyun
801*4882a593Smuzhiyun if (r) {
802*4882a593Smuzhiyun pt_req_sense(tape, 0);
803*4882a593Smuzhiyun return -EIO;
804*4882a593Smuzhiyun }
805*4882a593Smuzhiyun
806*4882a593Smuzhiyun while (1) {
807*4882a593Smuzhiyun
808*4882a593Smuzhiyun r = pt_wait(tape, STAT_BUSY,
809*4882a593Smuzhiyun STAT_DRQ | STAT_ERR | STAT_READY,
810*4882a593Smuzhiyun DBMSG("read DRQ"), "");
811*4882a593Smuzhiyun
812*4882a593Smuzhiyun if (r & STAT_SENSE) {
813*4882a593Smuzhiyun pi_disconnect(pi);
814*4882a593Smuzhiyun pt_req_sense(tape, 0);
815*4882a593Smuzhiyun return -EIO;
816*4882a593Smuzhiyun }
817*4882a593Smuzhiyun
818*4882a593Smuzhiyun if (r)
819*4882a593Smuzhiyun tape->flags |= PT_EOF;
820*4882a593Smuzhiyun
821*4882a593Smuzhiyun s = read_reg(pi, 7);
822*4882a593Smuzhiyun
823*4882a593Smuzhiyun if (!(s & STAT_DRQ))
824*4882a593Smuzhiyun break;
825*4882a593Smuzhiyun
826*4882a593Smuzhiyun n = (read_reg(pi, 4) + 256 * read_reg(pi, 5));
827*4882a593Smuzhiyun p = (read_reg(pi, 2) & 3);
828*4882a593Smuzhiyun if (p != 2) {
829*4882a593Smuzhiyun pi_disconnect(pi);
830*4882a593Smuzhiyun printk("%s: Phase error on read: %d\n", tape->name,
831*4882a593Smuzhiyun p);
832*4882a593Smuzhiyun return -EIO;
833*4882a593Smuzhiyun }
834*4882a593Smuzhiyun
835*4882a593Smuzhiyun while (n > 0) {
836*4882a593Smuzhiyun k = n;
837*4882a593Smuzhiyun if (k > PT_BUFSIZE)
838*4882a593Smuzhiyun k = PT_BUFSIZE;
839*4882a593Smuzhiyun pi_read_block(pi, tape->bufptr, k);
840*4882a593Smuzhiyun n -= k;
841*4882a593Smuzhiyun b = k;
842*4882a593Smuzhiyun if (b > count)
843*4882a593Smuzhiyun b = count;
844*4882a593Smuzhiyun if (copy_to_user(buf + t, tape->bufptr, b)) {
845*4882a593Smuzhiyun pi_disconnect(pi);
846*4882a593Smuzhiyun return -EFAULT;
847*4882a593Smuzhiyun }
848*4882a593Smuzhiyun t += b;
849*4882a593Smuzhiyun count -= b;
850*4882a593Smuzhiyun }
851*4882a593Smuzhiyun
852*4882a593Smuzhiyun }
853*4882a593Smuzhiyun pi_disconnect(pi);
854*4882a593Smuzhiyun if (tape->flags & PT_EOF)
855*4882a593Smuzhiyun break;
856*4882a593Smuzhiyun }
857*4882a593Smuzhiyun
858*4882a593Smuzhiyun return t;
859*4882a593Smuzhiyun
860*4882a593Smuzhiyun }
861*4882a593Smuzhiyun
pt_write(struct file * filp,const char __user * buf,size_t count,loff_t * ppos)862*4882a593Smuzhiyun static ssize_t pt_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
863*4882a593Smuzhiyun {
864*4882a593Smuzhiyun struct pt_unit *tape = filp->private_data;
865*4882a593Smuzhiyun struct pi_adapter *pi = tape->pi;
866*4882a593Smuzhiyun char wr_cmd[12] = { ATAPI_WRITE_6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
867*4882a593Smuzhiyun int k, n, r, p, s, t, b;
868*4882a593Smuzhiyun
869*4882a593Smuzhiyun if (!(tape->flags & PT_WRITE_OK))
870*4882a593Smuzhiyun return -EROFS;
871*4882a593Smuzhiyun
872*4882a593Smuzhiyun if (!(tape->flags & (PT_READING | PT_WRITING))) {
873*4882a593Smuzhiyun tape->flags |= PT_WRITING;
874*4882a593Smuzhiyun if (pt_atapi
875*4882a593Smuzhiyun (tape, wr_cmd, 0, NULL, "start buffer-available mode"))
876*4882a593Smuzhiyun return -EIO;
877*4882a593Smuzhiyun } else if (tape->flags & PT_READING)
878*4882a593Smuzhiyun return -EIO;
879*4882a593Smuzhiyun
880*4882a593Smuzhiyun if (tape->flags & PT_EOF)
881*4882a593Smuzhiyun return -ENOSPC;
882*4882a593Smuzhiyun
883*4882a593Smuzhiyun t = 0;
884*4882a593Smuzhiyun
885*4882a593Smuzhiyun while (count > 0) {
886*4882a593Smuzhiyun
887*4882a593Smuzhiyun if (!pt_poll_dsc(tape, HZ / 100, PT_TMO, "write"))
888*4882a593Smuzhiyun return -EIO;
889*4882a593Smuzhiyun
890*4882a593Smuzhiyun n = count;
891*4882a593Smuzhiyun if (n > 32768)
892*4882a593Smuzhiyun n = 32768; /* max per command */
893*4882a593Smuzhiyun b = (n - 1 + tape->bs) / tape->bs;
894*4882a593Smuzhiyun n = b * tape->bs; /* rounded up to even block */
895*4882a593Smuzhiyun
896*4882a593Smuzhiyun wr_cmd[4] = b;
897*4882a593Smuzhiyun
898*4882a593Smuzhiyun r = pt_command(tape, wr_cmd, n, "write");
899*4882a593Smuzhiyun
900*4882a593Smuzhiyun mdelay(1);
901*4882a593Smuzhiyun
902*4882a593Smuzhiyun if (r) { /* error delivering command only */
903*4882a593Smuzhiyun pt_req_sense(tape, 0);
904*4882a593Smuzhiyun return -EIO;
905*4882a593Smuzhiyun }
906*4882a593Smuzhiyun
907*4882a593Smuzhiyun while (1) {
908*4882a593Smuzhiyun
909*4882a593Smuzhiyun r = pt_wait(tape, STAT_BUSY,
910*4882a593Smuzhiyun STAT_DRQ | STAT_ERR | STAT_READY,
911*4882a593Smuzhiyun DBMSG("write DRQ"), NULL);
912*4882a593Smuzhiyun
913*4882a593Smuzhiyun if (r & STAT_SENSE) {
914*4882a593Smuzhiyun pi_disconnect(pi);
915*4882a593Smuzhiyun pt_req_sense(tape, 0);
916*4882a593Smuzhiyun return -EIO;
917*4882a593Smuzhiyun }
918*4882a593Smuzhiyun
919*4882a593Smuzhiyun if (r)
920*4882a593Smuzhiyun tape->flags |= PT_EOF;
921*4882a593Smuzhiyun
922*4882a593Smuzhiyun s = read_reg(pi, 7);
923*4882a593Smuzhiyun
924*4882a593Smuzhiyun if (!(s & STAT_DRQ))
925*4882a593Smuzhiyun break;
926*4882a593Smuzhiyun
927*4882a593Smuzhiyun n = (read_reg(pi, 4) + 256 * read_reg(pi, 5));
928*4882a593Smuzhiyun p = (read_reg(pi, 2) & 3);
929*4882a593Smuzhiyun if (p != 0) {
930*4882a593Smuzhiyun pi_disconnect(pi);
931*4882a593Smuzhiyun printk("%s: Phase error on write: %d \n",
932*4882a593Smuzhiyun tape->name, p);
933*4882a593Smuzhiyun return -EIO;
934*4882a593Smuzhiyun }
935*4882a593Smuzhiyun
936*4882a593Smuzhiyun while (n > 0) {
937*4882a593Smuzhiyun k = n;
938*4882a593Smuzhiyun if (k > PT_BUFSIZE)
939*4882a593Smuzhiyun k = PT_BUFSIZE;
940*4882a593Smuzhiyun b = k;
941*4882a593Smuzhiyun if (b > count)
942*4882a593Smuzhiyun b = count;
943*4882a593Smuzhiyun if (copy_from_user(tape->bufptr, buf + t, b)) {
944*4882a593Smuzhiyun pi_disconnect(pi);
945*4882a593Smuzhiyun return -EFAULT;
946*4882a593Smuzhiyun }
947*4882a593Smuzhiyun pi_write_block(pi, tape->bufptr, k);
948*4882a593Smuzhiyun t += b;
949*4882a593Smuzhiyun count -= b;
950*4882a593Smuzhiyun n -= k;
951*4882a593Smuzhiyun }
952*4882a593Smuzhiyun
953*4882a593Smuzhiyun }
954*4882a593Smuzhiyun pi_disconnect(pi);
955*4882a593Smuzhiyun if (tape->flags & PT_EOF)
956*4882a593Smuzhiyun break;
957*4882a593Smuzhiyun }
958*4882a593Smuzhiyun
959*4882a593Smuzhiyun return t;
960*4882a593Smuzhiyun }
961*4882a593Smuzhiyun
pt_init(void)962*4882a593Smuzhiyun static int __init pt_init(void)
963*4882a593Smuzhiyun {
964*4882a593Smuzhiyun int unit;
965*4882a593Smuzhiyun int err;
966*4882a593Smuzhiyun
967*4882a593Smuzhiyun if (disable) {
968*4882a593Smuzhiyun err = -EINVAL;
969*4882a593Smuzhiyun goto out;
970*4882a593Smuzhiyun }
971*4882a593Smuzhiyun
972*4882a593Smuzhiyun if (pt_detect()) {
973*4882a593Smuzhiyun err = -ENODEV;
974*4882a593Smuzhiyun goto out;
975*4882a593Smuzhiyun }
976*4882a593Smuzhiyun
977*4882a593Smuzhiyun err = register_chrdev(major, name, &pt_fops);
978*4882a593Smuzhiyun if (err < 0) {
979*4882a593Smuzhiyun printk("pt_init: unable to get major number %d\n", major);
980*4882a593Smuzhiyun for (unit = 0; unit < PT_UNITS; unit++)
981*4882a593Smuzhiyun if (pt[unit].present)
982*4882a593Smuzhiyun pi_release(pt[unit].pi);
983*4882a593Smuzhiyun goto out;
984*4882a593Smuzhiyun }
985*4882a593Smuzhiyun major = err;
986*4882a593Smuzhiyun pt_class = class_create(THIS_MODULE, "pt");
987*4882a593Smuzhiyun if (IS_ERR(pt_class)) {
988*4882a593Smuzhiyun err = PTR_ERR(pt_class);
989*4882a593Smuzhiyun goto out_chrdev;
990*4882a593Smuzhiyun }
991*4882a593Smuzhiyun
992*4882a593Smuzhiyun for (unit = 0; unit < PT_UNITS; unit++)
993*4882a593Smuzhiyun if (pt[unit].present) {
994*4882a593Smuzhiyun device_create(pt_class, NULL, MKDEV(major, unit), NULL,
995*4882a593Smuzhiyun "pt%d", unit);
996*4882a593Smuzhiyun device_create(pt_class, NULL, MKDEV(major, unit + 128),
997*4882a593Smuzhiyun NULL, "pt%dn", unit);
998*4882a593Smuzhiyun }
999*4882a593Smuzhiyun goto out;
1000*4882a593Smuzhiyun
1001*4882a593Smuzhiyun out_chrdev:
1002*4882a593Smuzhiyun unregister_chrdev(major, "pt");
1003*4882a593Smuzhiyun out:
1004*4882a593Smuzhiyun return err;
1005*4882a593Smuzhiyun }
1006*4882a593Smuzhiyun
pt_exit(void)1007*4882a593Smuzhiyun static void __exit pt_exit(void)
1008*4882a593Smuzhiyun {
1009*4882a593Smuzhiyun int unit;
1010*4882a593Smuzhiyun for (unit = 0; unit < PT_UNITS; unit++)
1011*4882a593Smuzhiyun if (pt[unit].present) {
1012*4882a593Smuzhiyun device_destroy(pt_class, MKDEV(major, unit));
1013*4882a593Smuzhiyun device_destroy(pt_class, MKDEV(major, unit + 128));
1014*4882a593Smuzhiyun }
1015*4882a593Smuzhiyun class_destroy(pt_class);
1016*4882a593Smuzhiyun unregister_chrdev(major, name);
1017*4882a593Smuzhiyun for (unit = 0; unit < PT_UNITS; unit++)
1018*4882a593Smuzhiyun if (pt[unit].present)
1019*4882a593Smuzhiyun pi_release(pt[unit].pi);
1020*4882a593Smuzhiyun }
1021*4882a593Smuzhiyun
1022*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1023*4882a593Smuzhiyun module_init(pt_init)
1024*4882a593Smuzhiyun module_exit(pt_exit)
1025