diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/block/paride/pf.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/block/paride/pf.c')
-rw-r--r-- | drivers/block/paride/pf.c | 982 |
1 files changed, 982 insertions, 0 deletions
diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c new file mode 100644 index 000000000000..060b1f2a91dd --- /dev/null +++ b/drivers/block/paride/pf.c | |||
@@ -0,0 +1,982 @@ | |||
1 | /* | ||
2 | pf.c (c) 1997-8 Grant R. Guenther <grant@torque.net> | ||
3 | Under the terms of the GNU General Public License. | ||
4 | |||
5 | This is the high-level driver for parallel port ATAPI disk | ||
6 | drives based on chips supported by the paride module. | ||
7 | |||
8 | By default, the driver will autoprobe for a single parallel | ||
9 | port ATAPI disk drive, but if their individual parameters are | ||
10 | specified, the driver can handle up to 4 drives. | ||
11 | |||
12 | The behaviour of the pf driver can be altered by setting | ||
13 | some parameters from the insmod command line. The following | ||
14 | parameters are adjustable: | ||
15 | |||
16 | drive0 These four arguments can be arrays of | ||
17 | drive1 1-7 integers as follows: | ||
18 | drive2 | ||
19 | drive3 <prt>,<pro>,<uni>,<mod>,<slv>,<lun>,<dly> | ||
20 | |||
21 | Where, | ||
22 | |||
23 | <prt> is the base of the parallel port address for | ||
24 | the corresponding drive. (required) | ||
25 | |||
26 | <pro> is the protocol number for the adapter that | ||
27 | supports this drive. These numbers are | ||
28 | logged by 'paride' when the protocol modules | ||
29 | are initialised. (0 if not given) | ||
30 | |||
31 | <uni> for those adapters that support chained | ||
32 | devices, this is the unit selector for the | ||
33 | chain of devices on the given port. It should | ||
34 | be zero for devices that don't support chaining. | ||
35 | (0 if not given) | ||
36 | |||
37 | <mod> this can be -1 to choose the best mode, or one | ||
38 | of the mode numbers supported by the adapter. | ||
39 | (-1 if not given) | ||
40 | |||
41 | <slv> ATAPI CDroms can be jumpered to master or slave. | ||
42 | Set this to 0 to choose the master drive, 1 to | ||
43 | choose the slave, -1 (the default) to choose the | ||
44 | first drive found. | ||
45 | |||
46 | <lun> Some ATAPI devices support multiple LUNs. | ||
47 | One example is the ATAPI PD/CD drive from | ||
48 | Matshita/Panasonic. This device has a | ||
49 | CD drive on LUN 0 and a PD drive on LUN 1. | ||
50 | By default, the driver will search for the | ||
51 | first LUN with a supported device. Set | ||
52 | this parameter to force it to use a specific | ||
53 | LUN. (default -1) | ||
54 | |||
55 | <dly> some parallel ports require the driver to | ||
56 | go more slowly. -1 sets a default value that | ||
57 | should work with the chosen protocol. Otherwise, | ||
58 | set this to a small integer, the larger it is | ||
59 | the slower the port i/o. In some cases, setting | ||
60 | this to zero will speed up the device. (default -1) | ||
61 | |||
62 | major You may use this parameter to overide the | ||
63 | default major number (47) that this driver | ||
64 | will use. Be sure to change the device | ||
65 | name as well. | ||
66 | |||
67 | name This parameter is a character string that | ||
68 | contains the name the kernel will use for this | ||
69 | device (in /proc output, for instance). | ||
70 | (default "pf"). | ||
71 | |||
72 | cluster The driver will attempt to aggregate requests | ||
73 | for adjacent blocks into larger multi-block | ||
74 | clusters. The maximum cluster size (in 512 | ||
75 | byte sectors) is set with this parameter. | ||
76 | (default 64) | ||
77 | |||
78 | verbose This parameter controls the amount of logging | ||
79 | that the driver will do. Set it to 0 for | ||
80 | normal operation, 1 to see autoprobe progress | ||
81 | messages, or 2 to see additional debugging | ||
82 | output. (default 0) | ||
83 | |||
84 | nice This parameter controls the driver's use of | ||
85 | idle CPU time, at the expense of some speed. | ||
86 | |||
87 | If this driver is built into the kernel, you can use the | ||
88 | following command line parameters, with the same values | ||
89 | as the corresponding module parameters listed above: | ||
90 | |||
91 | pf.drive0 | ||
92 | pf.drive1 | ||
93 | pf.drive2 | ||
94 | pf.drive3 | ||
95 | pf.cluster | ||
96 | pf.nice | ||
97 | |||
98 | In addition, you can use the parameter pf.disable to disable | ||
99 | the driver entirely. | ||
100 | |||
101 | */ | ||
102 | |||
103 | /* Changes: | ||
104 | |||
105 | 1.01 GRG 1998.05.03 Changes for SMP. Eliminate sti(). | ||
106 | Fix for drives that don't clear STAT_ERR | ||
107 | until after next CDB delivered. | ||
108 | Small change in pf_completion to round | ||
109 | up transfer size. | ||
110 | 1.02 GRG 1998.06.16 Eliminated an Ugh | ||
111 | 1.03 GRG 1998.08.16 Use HZ in loop timings, extra debugging | ||
112 | 1.04 GRG 1998.09.24 Added jumbo support | ||
113 | |||
114 | */ | ||
115 | |||
116 | #define PF_VERSION "1.04" | ||
117 | #define PF_MAJOR 47 | ||
118 | #define PF_NAME "pf" | ||
119 | #define PF_UNITS 4 | ||
120 | |||
121 | /* Here are things one can override from the insmod command. | ||
122 | Most are autoprobed by paride unless set here. Verbose is off | ||
123 | by default. | ||
124 | |||
125 | */ | ||
126 | |||
127 | static int verbose = 0; | ||
128 | static int major = PF_MAJOR; | ||
129 | static char *name = PF_NAME; | ||
130 | static int cluster = 64; | ||
131 | static int nice = 0; | ||
132 | static int disable = 0; | ||
133 | |||
134 | static int drive0[7] = { 0, 0, 0, -1, -1, -1, -1 }; | ||
135 | static int drive1[7] = { 0, 0, 0, -1, -1, -1, -1 }; | ||
136 | static int drive2[7] = { 0, 0, 0, -1, -1, -1, -1 }; | ||
137 | static int drive3[7] = { 0, 0, 0, -1, -1, -1, -1 }; | ||
138 | |||
139 | static int (*drives[4])[7] = {&drive0, &drive1, &drive2, &drive3}; | ||
140 | static int pf_drive_count; | ||
141 | |||
142 | enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_LUN, D_DLY}; | ||
143 | |||
144 | /* end of parameters */ | ||
145 | |||
146 | #include <linux/module.h> | ||
147 | #include <linux/init.h> | ||
148 | #include <linux/fs.h> | ||
149 | #include <linux/delay.h> | ||
150 | #include <linux/hdreg.h> | ||
151 | #include <linux/cdrom.h> | ||
152 | #include <linux/spinlock.h> | ||
153 | #include <linux/blkdev.h> | ||
154 | #include <linux/blkpg.h> | ||
155 | #include <asm/uaccess.h> | ||
156 | |||
157 | static spinlock_t pf_spin_lock; | ||
158 | |||
159 | module_param(verbose, bool, 0644); | ||
160 | module_param(major, int, 0); | ||
161 | module_param(name, charp, 0); | ||
162 | module_param(cluster, int, 0); | ||
163 | module_param(nice, int, 0); | ||
164 | module_param_array(drive0, int, NULL, 0); | ||
165 | module_param_array(drive1, int, NULL, 0); | ||
166 | module_param_array(drive2, int, NULL, 0); | ||
167 | module_param_array(drive3, int, NULL, 0); | ||
168 | |||
169 | #include "paride.h" | ||
170 | #include "pseudo.h" | ||
171 | |||
172 | /* constants for faking geometry numbers */ | ||
173 | |||
174 | #define PF_FD_MAX 8192 /* use FD geometry under this size */ | ||
175 | #define PF_FD_HDS 2 | ||
176 | #define PF_FD_SPT 18 | ||
177 | #define PF_HD_HDS 64 | ||
178 | #define PF_HD_SPT 32 | ||
179 | |||
180 | #define PF_MAX_RETRIES 5 | ||
181 | #define PF_TMO 800 /* interrupt timeout in jiffies */ | ||
182 | #define PF_SPIN_DEL 50 /* spin delay in micro-seconds */ | ||
183 | |||
184 | #define PF_SPIN (1000000*PF_TMO)/(HZ*PF_SPIN_DEL) | ||
185 | |||
186 | #define STAT_ERR 0x00001 | ||
187 | #define STAT_INDEX 0x00002 | ||
188 | #define STAT_ECC 0x00004 | ||
189 | #define STAT_DRQ 0x00008 | ||
190 | #define STAT_SEEK 0x00010 | ||
191 | #define STAT_WRERR 0x00020 | ||
192 | #define STAT_READY 0x00040 | ||
193 | #define STAT_BUSY 0x00080 | ||
194 | |||
195 | #define ATAPI_REQ_SENSE 0x03 | ||
196 | #define ATAPI_LOCK 0x1e | ||
197 | #define ATAPI_DOOR 0x1b | ||
198 | #define ATAPI_MODE_SENSE 0x5a | ||
199 | #define ATAPI_CAPACITY 0x25 | ||
200 | #define ATAPI_IDENTIFY 0x12 | ||
201 | #define ATAPI_READ_10 0x28 | ||
202 | #define ATAPI_WRITE_10 0x2a | ||
203 | |||
204 | static int pf_open(struct inode *inode, struct file *file); | ||
205 | static void do_pf_request(request_queue_t * q); | ||
206 | static int pf_ioctl(struct inode *inode, struct file *file, | ||
207 | unsigned int cmd, unsigned long arg); | ||
208 | |||
209 | static int pf_release(struct inode *inode, struct file *file); | ||
210 | |||
211 | static int pf_detect(void); | ||
212 | static void do_pf_read(void); | ||
213 | static void do_pf_read_start(void); | ||
214 | static void do_pf_write(void); | ||
215 | static void do_pf_write_start(void); | ||
216 | static void do_pf_read_drq(void); | ||
217 | static void do_pf_write_done(void); | ||
218 | |||
219 | #define PF_NM 0 | ||
220 | #define PF_RO 1 | ||
221 | #define PF_RW 2 | ||
222 | |||
223 | #define PF_NAMELEN 8 | ||
224 | |||
225 | struct pf_unit { | ||
226 | struct pi_adapter pia; /* interface to paride layer */ | ||
227 | struct pi_adapter *pi; | ||
228 | int removable; /* removable media device ? */ | ||
229 | int media_status; /* media present ? WP ? */ | ||
230 | int drive; /* drive */ | ||
231 | int lun; | ||
232 | int access; /* count of active opens ... */ | ||
233 | int present; /* device present ? */ | ||
234 | char name[PF_NAMELEN]; /* pf0, pf1, ... */ | ||
235 | struct gendisk *disk; | ||
236 | }; | ||
237 | |||
238 | static struct pf_unit units[PF_UNITS]; | ||
239 | |||
240 | static int pf_identify(struct pf_unit *pf); | ||
241 | static void pf_lock(struct pf_unit *pf, int func); | ||
242 | static void pf_eject(struct pf_unit *pf); | ||
243 | static int pf_check_media(struct gendisk *disk); | ||
244 | |||
245 | static char pf_scratch[512]; /* scratch block buffer */ | ||
246 | |||
247 | /* the variables below are used mainly in the I/O request engine, which | ||
248 | processes only one request at a time. | ||
249 | */ | ||
250 | |||
251 | static int pf_retries = 0; /* i/o error retry count */ | ||
252 | static int pf_busy = 0; /* request being processed ? */ | ||
253 | static struct request *pf_req; /* current request */ | ||
254 | static int pf_block; /* address of next requested block */ | ||
255 | static int pf_count; /* number of blocks still to do */ | ||
256 | static int pf_run; /* sectors in current cluster */ | ||
257 | static int pf_cmd; /* current command READ/WRITE */ | ||
258 | static struct pf_unit *pf_current;/* unit of current request */ | ||
259 | static int pf_mask; /* stopper for pseudo-int */ | ||
260 | static char *pf_buf; /* buffer for request in progress */ | ||
261 | |||
262 | /* kernel glue structures */ | ||
263 | |||
264 | static struct block_device_operations pf_fops = { | ||
265 | .owner = THIS_MODULE, | ||
266 | .open = pf_open, | ||
267 | .release = pf_release, | ||
268 | .ioctl = pf_ioctl, | ||
269 | .media_changed = pf_check_media, | ||
270 | }; | ||
271 | |||
272 | static void __init pf_init_units(void) | ||
273 | { | ||
274 | struct pf_unit *pf; | ||
275 | int unit; | ||
276 | |||
277 | pf_drive_count = 0; | ||
278 | for (unit = 0, pf = units; unit < PF_UNITS; unit++, pf++) { | ||
279 | struct gendisk *disk = alloc_disk(1); | ||
280 | if (!disk) | ||
281 | continue; | ||
282 | pf->disk = disk; | ||
283 | pf->pi = &pf->pia; | ||
284 | pf->media_status = PF_NM; | ||
285 | pf->drive = (*drives[unit])[D_SLV]; | ||
286 | pf->lun = (*drives[unit])[D_LUN]; | ||
287 | snprintf(pf->name, PF_NAMELEN, "%s%d", name, unit); | ||
288 | disk->major = major; | ||
289 | disk->first_minor = unit; | ||
290 | strcpy(disk->disk_name, pf->name); | ||
291 | disk->fops = &pf_fops; | ||
292 | if (!(*drives[unit])[D_PRT]) | ||
293 | pf_drive_count++; | ||
294 | } | ||
295 | } | ||
296 | |||
297 | static int pf_open(struct inode *inode, struct file *file) | ||
298 | { | ||
299 | struct pf_unit *pf = inode->i_bdev->bd_disk->private_data; | ||
300 | |||
301 | pf_identify(pf); | ||
302 | |||
303 | if (pf->media_status == PF_NM) | ||
304 | return -ENODEV; | ||
305 | |||
306 | if ((pf->media_status == PF_RO) && (file->f_mode & 2)) | ||
307 | return -EROFS; | ||
308 | |||
309 | pf->access++; | ||
310 | if (pf->removable) | ||
311 | pf_lock(pf, 1); | ||
312 | |||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | static int pf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) | ||
317 | { | ||
318 | struct pf_unit *pf = inode->i_bdev->bd_disk->private_data; | ||
319 | struct hd_geometry __user *geo = (struct hd_geometry __user *) arg; | ||
320 | struct hd_geometry g; | ||
321 | sector_t capacity; | ||
322 | |||
323 | if (cmd == CDROMEJECT) { | ||
324 | if (pf->access == 1) { | ||
325 | pf_eject(pf); | ||
326 | return 0; | ||
327 | } | ||
328 | return -EBUSY; | ||
329 | } | ||
330 | if (cmd != HDIO_GETGEO) | ||
331 | return -EINVAL; | ||
332 | capacity = get_capacity(pf->disk); | ||
333 | if (capacity < PF_FD_MAX) { | ||
334 | g.cylinders = sector_div(capacity, PF_FD_HDS * PF_FD_SPT); | ||
335 | g.heads = PF_FD_HDS; | ||
336 | g.sectors = PF_FD_SPT; | ||
337 | } else { | ||
338 | g.cylinders = sector_div(capacity, PF_HD_HDS * PF_HD_SPT); | ||
339 | g.heads = PF_HD_HDS; | ||
340 | g.sectors = PF_HD_SPT; | ||
341 | } | ||
342 | if (copy_to_user(geo, &g, sizeof(g))) | ||
343 | return -EFAULT; | ||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | static int pf_release(struct inode *inode, struct file *file) | ||
348 | { | ||
349 | struct pf_unit *pf = inode->i_bdev->bd_disk->private_data; | ||
350 | |||
351 | if (pf->access <= 0) | ||
352 | return -EINVAL; | ||
353 | |||
354 | pf->access--; | ||
355 | |||
356 | if (!pf->access && pf->removable) | ||
357 | pf_lock(pf, 0); | ||
358 | |||
359 | return 0; | ||
360 | |||
361 | } | ||
362 | |||
363 | static int pf_check_media(struct gendisk *disk) | ||
364 | { | ||
365 | return 1; | ||
366 | } | ||
367 | |||
368 | static inline int status_reg(struct pf_unit *pf) | ||
369 | { | ||
370 | return pi_read_regr(pf->pi, 1, 6); | ||
371 | } | ||
372 | |||
373 | static inline int read_reg(struct pf_unit *pf, int reg) | ||
374 | { | ||
375 | return pi_read_regr(pf->pi, 0, reg); | ||
376 | } | ||
377 | |||
378 | static inline void write_reg(struct pf_unit *pf, int reg, int val) | ||
379 | { | ||
380 | pi_write_regr(pf->pi, 0, reg, val); | ||
381 | } | ||
382 | |||
383 | static int pf_wait(struct pf_unit *pf, int go, int stop, char *fun, char *msg) | ||
384 | { | ||
385 | int j, r, e, s, p; | ||
386 | |||
387 | j = 0; | ||
388 | while ((((r = status_reg(pf)) & go) || (stop && (!(r & stop)))) | ||
389 | && (j++ < PF_SPIN)) | ||
390 | udelay(PF_SPIN_DEL); | ||
391 | |||
392 | if ((r & (STAT_ERR & stop)) || (j >= PF_SPIN)) { | ||
393 | s = read_reg(pf, 7); | ||
394 | e = read_reg(pf, 1); | ||
395 | p = read_reg(pf, 2); | ||
396 | if (j >= PF_SPIN) | ||
397 | e |= 0x100; | ||
398 | if (fun) | ||
399 | printk("%s: %s %s: alt=0x%x stat=0x%x err=0x%x" | ||
400 | " loop=%d phase=%d\n", | ||
401 | pf->name, fun, msg, r, s, e, j, p); | ||
402 | return (e << 8) + s; | ||
403 | } | ||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | static int pf_command(struct pf_unit *pf, char *cmd, int dlen, char *fun) | ||
408 | { | ||
409 | pi_connect(pf->pi); | ||
410 | |||
411 | write_reg(pf, 6, 0xa0+0x10*pf->drive); | ||
412 | |||
413 | if (pf_wait(pf, STAT_BUSY | STAT_DRQ, 0, fun, "before command")) { | ||
414 | pi_disconnect(pf->pi); | ||
415 | return -1; | ||
416 | } | ||
417 | |||
418 | write_reg(pf, 4, dlen % 256); | ||
419 | write_reg(pf, 5, dlen / 256); | ||
420 | write_reg(pf, 7, 0xa0); /* ATAPI packet command */ | ||
421 | |||
422 | if (pf_wait(pf, STAT_BUSY, STAT_DRQ, fun, "command DRQ")) { | ||
423 | pi_disconnect(pf->pi); | ||
424 | return -1; | ||
425 | } | ||
426 | |||
427 | if (read_reg(pf, 2) != 1) { | ||
428 | printk("%s: %s: command phase error\n", pf->name, fun); | ||
429 | pi_disconnect(pf->pi); | ||
430 | return -1; | ||
431 | } | ||
432 | |||
433 | pi_write_block(pf->pi, cmd, 12); | ||
434 | |||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | static int pf_completion(struct pf_unit *pf, char *buf, char *fun) | ||
439 | { | ||
440 | int r, s, n; | ||
441 | |||
442 | r = pf_wait(pf, STAT_BUSY, STAT_DRQ | STAT_READY | STAT_ERR, | ||
443 | fun, "completion"); | ||
444 | |||
445 | if ((read_reg(pf, 2) & 2) && (read_reg(pf, 7) & STAT_DRQ)) { | ||
446 | n = (((read_reg(pf, 4) + 256 * read_reg(pf, 5)) + | ||
447 | 3) & 0xfffc); | ||
448 | pi_read_block(pf->pi, buf, n); | ||
449 | } | ||
450 | |||
451 | s = pf_wait(pf, STAT_BUSY, STAT_READY | STAT_ERR, fun, "data done"); | ||
452 | |||
453 | pi_disconnect(pf->pi); | ||
454 | |||
455 | return (r ? r : s); | ||
456 | } | ||
457 | |||
458 | static void pf_req_sense(struct pf_unit *pf, int quiet) | ||
459 | { | ||
460 | char rs_cmd[12] = | ||
461 | { ATAPI_REQ_SENSE, pf->lun << 5, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0 }; | ||
462 | char buf[16]; | ||
463 | int r; | ||
464 | |||
465 | r = pf_command(pf, rs_cmd, 16, "Request sense"); | ||
466 | mdelay(1); | ||
467 | if (!r) | ||
468 | pf_completion(pf, buf, "Request sense"); | ||
469 | |||
470 | if ((!r) && (!quiet)) | ||
471 | printk("%s: Sense key: %x, ASC: %x, ASQ: %x\n", | ||
472 | pf->name, buf[2] & 0xf, buf[12], buf[13]); | ||
473 | } | ||
474 | |||
475 | static int pf_atapi(struct pf_unit *pf, char *cmd, int dlen, char *buf, char *fun) | ||
476 | { | ||
477 | int r; | ||
478 | |||
479 | r = pf_command(pf, cmd, dlen, fun); | ||
480 | mdelay(1); | ||
481 | if (!r) | ||
482 | r = pf_completion(pf, buf, fun); | ||
483 | if (r) | ||
484 | pf_req_sense(pf, !fun); | ||
485 | |||
486 | return r; | ||
487 | } | ||
488 | |||
489 | #define DBMSG(msg) ((verbose>1)?(msg):NULL) | ||
490 | |||
491 | static void pf_lock(struct pf_unit *pf, int func) | ||
492 | { | ||
493 | char lo_cmd[12] = { ATAPI_LOCK, pf->lun << 5, 0, 0, func, 0, 0, 0, 0, 0, 0, 0 }; | ||
494 | |||
495 | pf_atapi(pf, lo_cmd, 0, pf_scratch, func ? "unlock" : "lock"); | ||
496 | } | ||
497 | |||
498 | static void pf_eject(struct pf_unit *pf) | ||
499 | { | ||
500 | char ej_cmd[12] = { ATAPI_DOOR, pf->lun << 5, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0 }; | ||
501 | |||
502 | pf_lock(pf, 0); | ||
503 | pf_atapi(pf, ej_cmd, 0, pf_scratch, "eject"); | ||
504 | } | ||
505 | |||
506 | #define PF_RESET_TMO 30 /* in tenths of a second */ | ||
507 | |||
508 | static void pf_sleep(int cs) | ||
509 | { | ||
510 | current->state = TASK_INTERRUPTIBLE; | ||
511 | schedule_timeout(cs); | ||
512 | } | ||
513 | |||
514 | /* the ATAPI standard actually specifies the contents of all 7 registers | ||
515 | after a reset, but the specification is ambiguous concerning the last | ||
516 | two bytes, and different drives interpret the standard differently. | ||
517 | */ | ||
518 | |||
519 | static int pf_reset(struct pf_unit *pf) | ||
520 | { | ||
521 | int i, k, flg; | ||
522 | int expect[5] = { 1, 1, 1, 0x14, 0xeb }; | ||
523 | |||
524 | pi_connect(pf->pi); | ||
525 | write_reg(pf, 6, 0xa0+0x10*pf->drive); | ||
526 | write_reg(pf, 7, 8); | ||
527 | |||
528 | pf_sleep(20 * HZ / 1000); | ||
529 | |||
530 | k = 0; | ||
531 | while ((k++ < PF_RESET_TMO) && (status_reg(pf) & STAT_BUSY)) | ||
532 | pf_sleep(HZ / 10); | ||
533 | |||
534 | flg = 1; | ||
535 | for (i = 0; i < 5; i++) | ||
536 | flg &= (read_reg(pf, i + 1) == expect[i]); | ||
537 | |||
538 | if (verbose) { | ||
539 | printk("%s: Reset (%d) signature = ", pf->name, k); | ||
540 | for (i = 0; i < 5; i++) | ||
541 | printk("%3x", read_reg(pf, i + 1)); | ||
542 | if (!flg) | ||
543 | printk(" (incorrect)"); | ||
544 | printk("\n"); | ||
545 | } | ||
546 | |||
547 | pi_disconnect(pf->pi); | ||
548 | return flg - 1; | ||
549 | } | ||
550 | |||
551 | static void pf_mode_sense(struct pf_unit *pf) | ||
552 | { | ||
553 | char ms_cmd[12] = | ||
554 | { ATAPI_MODE_SENSE, pf->lun << 5, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0 }; | ||
555 | char buf[8]; | ||
556 | |||
557 | pf_atapi(pf, ms_cmd, 8, buf, DBMSG("mode sense")); | ||
558 | pf->media_status = PF_RW; | ||
559 | if (buf[3] & 0x80) | ||
560 | pf->media_status = PF_RO; | ||
561 | } | ||
562 | |||
563 | static void xs(char *buf, char *targ, int offs, int len) | ||
564 | { | ||
565 | int j, k, l; | ||
566 | |||
567 | j = 0; | ||
568 | l = 0; | ||
569 | for (k = 0; k < len; k++) | ||
570 | if ((buf[k + offs] != 0x20) || (buf[k + offs] != l)) | ||
571 | l = targ[j++] = buf[k + offs]; | ||
572 | if (l == 0x20) | ||
573 | j--; | ||
574 | targ[j] = 0; | ||
575 | } | ||
576 | |||
577 | static int xl(char *buf, int offs) | ||
578 | { | ||
579 | int v, k; | ||
580 | |||
581 | v = 0; | ||
582 | for (k = 0; k < 4; k++) | ||
583 | v = v * 256 + (buf[k + offs] & 0xff); | ||
584 | return v; | ||
585 | } | ||
586 | |||
587 | static void pf_get_capacity(struct pf_unit *pf) | ||
588 | { | ||
589 | char rc_cmd[12] = { ATAPI_CAPACITY, pf->lun << 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | ||
590 | char buf[8]; | ||
591 | int bs; | ||
592 | |||
593 | if (pf_atapi(pf, rc_cmd, 8, buf, DBMSG("get capacity"))) { | ||
594 | pf->media_status = PF_NM; | ||
595 | return; | ||
596 | } | ||
597 | set_capacity(pf->disk, xl(buf, 0) + 1); | ||
598 | bs = xl(buf, 4); | ||
599 | if (bs != 512) { | ||
600 | set_capacity(pf->disk, 0); | ||
601 | if (verbose) | ||
602 | printk("%s: Drive %d, LUN %d," | ||
603 | " unsupported block size %d\n", | ||
604 | pf->name, pf->drive, pf->lun, bs); | ||
605 | } | ||
606 | } | ||
607 | |||
608 | static int pf_identify(struct pf_unit *pf) | ||
609 | { | ||
610 | int dt, s; | ||
611 | char *ms[2] = { "master", "slave" }; | ||
612 | char mf[10], id[18]; | ||
613 | char id_cmd[12] = | ||
614 | { ATAPI_IDENTIFY, pf->lun << 5, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0 }; | ||
615 | char buf[36]; | ||
616 | |||
617 | s = pf_atapi(pf, id_cmd, 36, buf, "identify"); | ||
618 | if (s) | ||
619 | return -1; | ||
620 | |||
621 | dt = buf[0] & 0x1f; | ||
622 | if ((dt != 0) && (dt != 7)) { | ||
623 | if (verbose) | ||
624 | printk("%s: Drive %d, LUN %d, unsupported type %d\n", | ||
625 | pf->name, pf->drive, pf->lun, dt); | ||
626 | return -1; | ||
627 | } | ||
628 | |||
629 | xs(buf, mf, 8, 8); | ||
630 | xs(buf, id, 16, 16); | ||
631 | |||
632 | pf->removable = (buf[1] & 0x80); | ||
633 | |||
634 | pf_mode_sense(pf); | ||
635 | pf_mode_sense(pf); | ||
636 | pf_mode_sense(pf); | ||
637 | |||
638 | pf_get_capacity(pf); | ||
639 | |||
640 | printk("%s: %s %s, %s LUN %d, type %d", | ||
641 | pf->name, mf, id, ms[pf->drive], pf->lun, dt); | ||
642 | if (pf->removable) | ||
643 | printk(", removable"); | ||
644 | if (pf->media_status == PF_NM) | ||
645 | printk(", no media\n"); | ||
646 | else { | ||
647 | if (pf->media_status == PF_RO) | ||
648 | printk(", RO"); | ||
649 | printk(", %llu blocks\n", | ||
650 | (unsigned long long)get_capacity(pf->disk)); | ||
651 | } | ||
652 | return 0; | ||
653 | } | ||
654 | |||
655 | /* returns 0, with id set if drive is detected | ||
656 | -1, if drive detection failed | ||
657 | */ | ||
658 | static int pf_probe(struct pf_unit *pf) | ||
659 | { | ||
660 | if (pf->drive == -1) { | ||
661 | for (pf->drive = 0; pf->drive <= 1; pf->drive++) | ||
662 | if (!pf_reset(pf)) { | ||
663 | if (pf->lun != -1) | ||
664 | return pf_identify(pf); | ||
665 | else | ||
666 | for (pf->lun = 0; pf->lun < 8; pf->lun++) | ||
667 | if (!pf_identify(pf)) | ||
668 | return 0; | ||
669 | } | ||
670 | } else { | ||
671 | if (pf_reset(pf)) | ||
672 | return -1; | ||
673 | if (pf->lun != -1) | ||
674 | return pf_identify(pf); | ||
675 | for (pf->lun = 0; pf->lun < 8; pf->lun++) | ||
676 | if (!pf_identify(pf)) | ||
677 | return 0; | ||
678 | } | ||
679 | return -1; | ||
680 | } | ||
681 | |||
682 | static int pf_detect(void) | ||
683 | { | ||
684 | struct pf_unit *pf = units; | ||
685 | int k, unit; | ||
686 | |||
687 | printk("%s: %s version %s, major %d, cluster %d, nice %d\n", | ||
688 | name, name, PF_VERSION, major, cluster, nice); | ||
689 | |||
690 | k = 0; | ||
691 | if (pf_drive_count == 0) { | ||
692 | if (pi_init(pf->pi, 1, -1, -1, -1, -1, -1, pf_scratch, PI_PF, | ||
693 | verbose, pf->name)) { | ||
694 | if (!pf_probe(pf) && pf->disk) { | ||
695 | pf->present = 1; | ||
696 | k++; | ||
697 | } else | ||
698 | pi_release(pf->pi); | ||
699 | } | ||
700 | |||
701 | } else | ||
702 | for (unit = 0; unit < PF_UNITS; unit++, pf++) { | ||
703 | int *conf = *drives[unit]; | ||
704 | if (!conf[D_PRT]) | ||
705 | continue; | ||
706 | if (pi_init(pf->pi, 0, conf[D_PRT], conf[D_MOD], | ||
707 | conf[D_UNI], conf[D_PRO], conf[D_DLY], | ||
708 | pf_scratch, PI_PF, verbose, pf->name)) { | ||
709 | if (!pf_probe(pf) && pf->disk) { | ||
710 | pf->present = 1; | ||
711 | k++; | ||
712 | } else | ||
713 | pi_release(pf->pi); | ||
714 | } | ||
715 | } | ||
716 | if (k) | ||
717 | return 0; | ||
718 | |||
719 | printk("%s: No ATAPI disk detected\n", name); | ||
720 | for (pf = units, unit = 0; unit < PF_UNITS; pf++, unit++) | ||
721 | put_disk(pf->disk); | ||
722 | return -1; | ||
723 | } | ||
724 | |||
725 | /* The i/o request engine */ | ||
726 | |||
727 | static int pf_start(struct pf_unit *pf, int cmd, int b, int c) | ||
728 | { | ||
729 | int i; | ||
730 | char io_cmd[12] = { cmd, pf->lun << 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; | ||
731 | |||
732 | for (i = 0; i < 4; i++) { | ||
733 | io_cmd[5 - i] = b & 0xff; | ||
734 | b = b >> 8; | ||
735 | } | ||
736 | |||
737 | io_cmd[8] = c & 0xff; | ||
738 | io_cmd[7] = (c >> 8) & 0xff; | ||
739 | |||
740 | i = pf_command(pf, io_cmd, c * 512, "start i/o"); | ||
741 | |||
742 | mdelay(1); | ||
743 | |||
744 | return i; | ||
745 | } | ||
746 | |||
747 | static int pf_ready(void) | ||
748 | { | ||
749 | return (((status_reg(pf_current) & (STAT_BUSY | pf_mask)) == pf_mask)); | ||
750 | } | ||
751 | |||
752 | static struct request_queue *pf_queue; | ||
753 | |||
754 | static void do_pf_request(request_queue_t * q) | ||
755 | { | ||
756 | if (pf_busy) | ||
757 | return; | ||
758 | repeat: | ||
759 | pf_req = elv_next_request(q); | ||
760 | if (!pf_req) | ||
761 | return; | ||
762 | |||
763 | pf_current = pf_req->rq_disk->private_data; | ||
764 | pf_block = pf_req->sector; | ||
765 | pf_run = pf_req->nr_sectors; | ||
766 | pf_count = pf_req->current_nr_sectors; | ||
767 | |||
768 | if (pf_block + pf_count > get_capacity(pf_req->rq_disk)) { | ||
769 | end_request(pf_req, 0); | ||
770 | goto repeat; | ||
771 | } | ||
772 | |||
773 | pf_cmd = rq_data_dir(pf_req); | ||
774 | pf_buf = pf_req->buffer; | ||
775 | pf_retries = 0; | ||
776 | |||
777 | pf_busy = 1; | ||
778 | if (pf_cmd == READ) | ||
779 | pi_do_claimed(pf_current->pi, do_pf_read); | ||
780 | else if (pf_cmd == WRITE) | ||
781 | pi_do_claimed(pf_current->pi, do_pf_write); | ||
782 | else { | ||
783 | pf_busy = 0; | ||
784 | end_request(pf_req, 0); | ||
785 | goto repeat; | ||
786 | } | ||
787 | } | ||
788 | |||
789 | static int pf_next_buf(void) | ||
790 | { | ||
791 | unsigned long saved_flags; | ||
792 | |||
793 | pf_count--; | ||
794 | pf_run--; | ||
795 | pf_buf += 512; | ||
796 | pf_block++; | ||
797 | if (!pf_run) | ||
798 | return 0; | ||
799 | if (!pf_count) | ||
800 | return 1; | ||
801 | spin_lock_irqsave(&pf_spin_lock, saved_flags); | ||
802 | end_request(pf_req, 1); | ||
803 | pf_count = pf_req->current_nr_sectors; | ||
804 | pf_buf = pf_req->buffer; | ||
805 | spin_unlock_irqrestore(&pf_spin_lock, saved_flags); | ||
806 | return 1; | ||
807 | } | ||
808 | |||
809 | static inline void next_request(int success) | ||
810 | { | ||
811 | unsigned long saved_flags; | ||
812 | |||
813 | spin_lock_irqsave(&pf_spin_lock, saved_flags); | ||
814 | end_request(pf_req, success); | ||
815 | pf_busy = 0; | ||
816 | do_pf_request(pf_queue); | ||
817 | spin_unlock_irqrestore(&pf_spin_lock, saved_flags); | ||
818 | } | ||
819 | |||
820 | /* detach from the calling context - in case the spinlock is held */ | ||
821 | static void do_pf_read(void) | ||
822 | { | ||
823 | ps_set_intr(do_pf_read_start, NULL, 0, nice); | ||
824 | } | ||
825 | |||
826 | static void do_pf_read_start(void) | ||
827 | { | ||
828 | pf_busy = 1; | ||
829 | |||
830 | if (pf_start(pf_current, ATAPI_READ_10, pf_block, pf_run)) { | ||
831 | pi_disconnect(pf_current->pi); | ||
832 | if (pf_retries < PF_MAX_RETRIES) { | ||
833 | pf_retries++; | ||
834 | pi_do_claimed(pf_current->pi, do_pf_read_start); | ||
835 | return; | ||
836 | } | ||
837 | next_request(0); | ||
838 | return; | ||
839 | } | ||
840 | pf_mask = STAT_DRQ; | ||
841 | ps_set_intr(do_pf_read_drq, pf_ready, PF_TMO, nice); | ||
842 | } | ||
843 | |||
844 | static void do_pf_read_drq(void) | ||
845 | { | ||
846 | while (1) { | ||
847 | if (pf_wait(pf_current, STAT_BUSY, STAT_DRQ | STAT_ERR, | ||
848 | "read block", "completion") & STAT_ERR) { | ||
849 | pi_disconnect(pf_current->pi); | ||
850 | if (pf_retries < PF_MAX_RETRIES) { | ||
851 | pf_req_sense(pf_current, 0); | ||
852 | pf_retries++; | ||
853 | pi_do_claimed(pf_current->pi, do_pf_read_start); | ||
854 | return; | ||
855 | } | ||
856 | next_request(0); | ||
857 | return; | ||
858 | } | ||
859 | pi_read_block(pf_current->pi, pf_buf, 512); | ||
860 | if (pf_next_buf()) | ||
861 | break; | ||
862 | } | ||
863 | pi_disconnect(pf_current->pi); | ||
864 | next_request(1); | ||
865 | } | ||
866 | |||
867 | static void do_pf_write(void) | ||
868 | { | ||
869 | ps_set_intr(do_pf_write_start, NULL, 0, nice); | ||
870 | } | ||
871 | |||
872 | static void do_pf_write_start(void) | ||
873 | { | ||
874 | pf_busy = 1; | ||
875 | |||
876 | if (pf_start(pf_current, ATAPI_WRITE_10, pf_block, pf_run)) { | ||
877 | pi_disconnect(pf_current->pi); | ||
878 | if (pf_retries < PF_MAX_RETRIES) { | ||
879 | pf_retries++; | ||
880 | pi_do_claimed(pf_current->pi, do_pf_write_start); | ||
881 | return; | ||
882 | } | ||
883 | next_request(0); | ||
884 | return; | ||
885 | } | ||
886 | |||
887 | while (1) { | ||
888 | if (pf_wait(pf_current, STAT_BUSY, STAT_DRQ | STAT_ERR, | ||
889 | "write block", "data wait") & STAT_ERR) { | ||
890 | pi_disconnect(pf_current->pi); | ||
891 | if (pf_retries < PF_MAX_RETRIES) { | ||
892 | pf_retries++; | ||
893 | pi_do_claimed(pf_current->pi, do_pf_write_start); | ||
894 | return; | ||
895 | } | ||
896 | next_request(0); | ||
897 | return; | ||
898 | } | ||
899 | pi_write_block(pf_current->pi, pf_buf, 512); | ||
900 | if (pf_next_buf()) | ||
901 | break; | ||
902 | } | ||
903 | pf_mask = 0; | ||
904 | ps_set_intr(do_pf_write_done, pf_ready, PF_TMO, nice); | ||
905 | } | ||
906 | |||
907 | static void do_pf_write_done(void) | ||
908 | { | ||
909 | if (pf_wait(pf_current, STAT_BUSY, 0, "write block", "done") & STAT_ERR) { | ||
910 | pi_disconnect(pf_current->pi); | ||
911 | if (pf_retries < PF_MAX_RETRIES) { | ||
912 | pf_retries++; | ||
913 | pi_do_claimed(pf_current->pi, do_pf_write_start); | ||
914 | return; | ||
915 | } | ||
916 | next_request(0); | ||
917 | return; | ||
918 | } | ||
919 | pi_disconnect(pf_current->pi); | ||
920 | next_request(1); | ||
921 | } | ||
922 | |||
923 | static int __init pf_init(void) | ||
924 | { /* preliminary initialisation */ | ||
925 | struct pf_unit *pf; | ||
926 | int unit; | ||
927 | |||
928 | if (disable) | ||
929 | return -1; | ||
930 | |||
931 | pf_init_units(); | ||
932 | |||
933 | if (pf_detect()) | ||
934 | return -1; | ||
935 | pf_busy = 0; | ||
936 | |||
937 | if (register_blkdev(major, name)) { | ||
938 | for (pf = units, unit = 0; unit < PF_UNITS; pf++, unit++) | ||
939 | put_disk(pf->disk); | ||
940 | return -1; | ||
941 | } | ||
942 | pf_queue = blk_init_queue(do_pf_request, &pf_spin_lock); | ||
943 | if (!pf_queue) { | ||
944 | unregister_blkdev(major, name); | ||
945 | for (pf = units, unit = 0; unit < PF_UNITS; pf++, unit++) | ||
946 | put_disk(pf->disk); | ||
947 | return -1; | ||
948 | } | ||
949 | |||
950 | blk_queue_max_phys_segments(pf_queue, cluster); | ||
951 | blk_queue_max_hw_segments(pf_queue, cluster); | ||
952 | |||
953 | for (pf = units, unit = 0; unit < PF_UNITS; pf++, unit++) { | ||
954 | struct gendisk *disk = pf->disk; | ||
955 | |||
956 | if (!pf->present) | ||
957 | continue; | ||
958 | disk->private_data = pf; | ||
959 | disk->queue = pf_queue; | ||
960 | add_disk(disk); | ||
961 | } | ||
962 | return 0; | ||
963 | } | ||
964 | |||
965 | static void __exit pf_exit(void) | ||
966 | { | ||
967 | struct pf_unit *pf; | ||
968 | int unit; | ||
969 | unregister_blkdev(major, name); | ||
970 | for (pf = units, unit = 0; unit < PF_UNITS; pf++, unit++) { | ||
971 | if (!pf->present) | ||
972 | continue; | ||
973 | del_gendisk(pf->disk); | ||
974 | put_disk(pf->disk); | ||
975 | pi_release(pf->pi); | ||
976 | } | ||
977 | blk_cleanup_queue(pf_queue); | ||
978 | } | ||
979 | |||
980 | MODULE_LICENSE("GPL"); | ||
981 | module_init(pf_init) | ||
982 | module_exit(pf_exit) | ||