1 |
1626 |
jcastillo |
/* -*- linux-c -*-
|
2 |
|
|
* linux/drivers/block/promise.c Version 0.07 Mar 26, 1996
|
3 |
|
|
*
|
4 |
|
|
* Copyright (C) 1995-1996 Linus Torvalds & authors (see below)
|
5 |
|
|
*/
|
6 |
|
|
|
7 |
|
|
/*
|
8 |
|
|
* Principal Author/Maintainer: peterd@pnd-pc.demon.co.uk
|
9 |
|
|
*
|
10 |
|
|
* This file provides support for the second port and cache of Promise
|
11 |
|
|
* IDE interfaces, e.g. DC4030, DC5030.
|
12 |
|
|
*
|
13 |
|
|
* Thanks are due to Mark Lord for advice and patiently answering stupid
|
14 |
|
|
* questions, and all those mugs^H^H^H^Hbrave souls who've tested this.
|
15 |
|
|
*
|
16 |
|
|
* Version 0.01 Initial version, #include'd in ide.c rather than
|
17 |
|
|
* compiled separately.
|
18 |
|
|
* Reads use Promise commands, writes as before. Drives
|
19 |
|
|
* on second channel are read-only.
|
20 |
|
|
* Version 0.02 Writes working on second channel, reads on both
|
21 |
|
|
* channels. Writes fail under high load. Suspect
|
22 |
|
|
* transfers of >127 sectors don't work.
|
23 |
|
|
* Version 0.03 Brought into line with ide.c version 5.27.
|
24 |
|
|
* Other minor changes.
|
25 |
|
|
* Version 0.04 Updated for ide.c version 5.30
|
26 |
|
|
* Changed initialization strategy
|
27 |
|
|
* Version 0.05 Kernel integration. -ml
|
28 |
|
|
* Version 0.06 Ooops. Add hwgroup to direct call of ide_intr() -ml
|
29 |
|
|
* Version 0.07 Added support for DC4030 variants
|
30 |
|
|
* Secondary interface autodetection
|
31 |
|
|
*/
|
32 |
|
|
|
33 |
|
|
/*
|
34 |
|
|
* Once you've compiled it in, you'll have to also enable the interface
|
35 |
|
|
* setup routine from the kernel command line, as in
|
36 |
|
|
*
|
37 |
|
|
* 'linux ide0=dc4030'
|
38 |
|
|
*
|
39 |
|
|
* As before, it seems that somewhere around 3Megs when writing, bad things
|
40 |
|
|
* start to happen [timeouts/retries -ml]. If anyone can give me more feedback,
|
41 |
|
|
* I'd really appreciate it. [email: peterd@pnd-pc.demon.co.uk]
|
42 |
|
|
*
|
43 |
|
|
*/
|
44 |
|
|
|
45 |
|
|
|
46 |
|
|
#undef REALLY_SLOW_IO /* most systems can safely undef this */
|
47 |
|
|
|
48 |
|
|
#include <linux/types.h>
|
49 |
|
|
#include <linux/kernel.h>
|
50 |
|
|
#include <linux/delay.h>
|
51 |
|
|
#include <linux/timer.h>
|
52 |
|
|
#include <linux/mm.h>
|
53 |
|
|
#include <linux/ioport.h>
|
54 |
|
|
#include <linux/blkdev.h>
|
55 |
|
|
#include <linux/hdreg.h>
|
56 |
|
|
#include <asm/io.h>
|
57 |
|
|
#include <asm/irq.h>
|
58 |
|
|
#include "ide.h"
|
59 |
|
|
#include "promise.h"
|
60 |
|
|
|
61 |
|
|
/* This is needed as the controller may not interrupt if the required data is
|
62 |
|
|
available in the cache. We have to simulate an interrupt. Ugh! */
|
63 |
|
|
|
64 |
|
|
extern void ide_intr(int, void *dev_id, struct pt_regs*);
|
65 |
|
|
|
66 |
|
|
/*
|
67 |
|
|
* promise_selectproc() is invoked by ide.c
|
68 |
|
|
* in preparation for access to the specified drive.
|
69 |
|
|
*/
|
70 |
|
|
static void promise_selectproc (ide_drive_t *drive)
|
71 |
|
|
{
|
72 |
|
|
unsigned int number;
|
73 |
|
|
|
74 |
|
|
OUT_BYTE(drive->select.all,IDE_SELECT_REG);
|
75 |
|
|
udelay(1); /* paranoia */
|
76 |
|
|
number = ((HWIF(drive)->is_promise2)<<1) + drive->select.b.unit;
|
77 |
|
|
OUT_BYTE(number,IDE_FEATURE_REG);
|
78 |
|
|
}
|
79 |
|
|
|
80 |
|
|
/*
|
81 |
|
|
* promise_cmd handles the set of vendor specific commands that are initiated
|
82 |
|
|
* by command F0. They all have the same success/failure notification.
|
83 |
|
|
*/
|
84 |
|
|
int promise_cmd(ide_drive_t *drive, byte cmd)
|
85 |
|
|
{
|
86 |
|
|
unsigned long timeout, timer;
|
87 |
|
|
byte status_val;
|
88 |
|
|
|
89 |
|
|
promise_selectproc(drive); /* redundant? */
|
90 |
|
|
OUT_BYTE(0xF3,IDE_SECTOR_REG);
|
91 |
|
|
OUT_BYTE(cmd,IDE_SELECT_REG);
|
92 |
|
|
OUT_BYTE(PROMISE_EXTENDED_COMMAND,IDE_COMMAND_REG);
|
93 |
|
|
timeout = HZ * 10;
|
94 |
|
|
timeout += jiffies;
|
95 |
|
|
do {
|
96 |
|
|
if(jiffies > timeout) {
|
97 |
|
|
return 2; /* device timed out */
|
98 |
|
|
}
|
99 |
|
|
/* This is out of delay_10ms() */
|
100 |
|
|
/* Delays at least 10ms to give interface a chance */
|
101 |
|
|
timer = jiffies + (HZ + 99)/100 + 1;
|
102 |
|
|
while (timer > jiffies);
|
103 |
|
|
status_val = IN_BYTE(IDE_SECTOR_REG);
|
104 |
|
|
} while (status_val != 0x50 && status_val != 0x70);
|
105 |
|
|
|
106 |
|
|
if(status_val == 0x50)
|
107 |
|
|
return 0; /* device returned success */
|
108 |
|
|
else
|
109 |
|
|
return 1; /* device returned failure */
|
110 |
|
|
}
|
111 |
|
|
|
112 |
|
|
ide_hwif_t *hwif_required = NULL;
|
113 |
|
|
|
114 |
|
|
void setup_dc4030 (ide_hwif_t *hwif)
|
115 |
|
|
{
|
116 |
|
|
hwif_required = hwif;
|
117 |
|
|
}
|
118 |
|
|
|
119 |
|
|
/*
|
120 |
|
|
init_dc4030: Test for presence of a Promise caching controller card.
|
121 |
|
|
Returns: 0 if no Promise card present at this io_base
|
122 |
|
|
1 if Promise card found
|
123 |
|
|
*/
|
124 |
|
|
int init_dc4030 (void)
|
125 |
|
|
{
|
126 |
|
|
ide_hwif_t *hwif = hwif_required;
|
127 |
|
|
ide_drive_t *drive;
|
128 |
|
|
ide_hwif_t *second_hwif;
|
129 |
|
|
struct dc_ident ident;
|
130 |
|
|
int i;
|
131 |
|
|
|
132 |
|
|
if (!hwif) return 0;
|
133 |
|
|
|
134 |
|
|
drive = &hwif->drives[0];
|
135 |
|
|
second_hwif = &ide_hwifs[hwif->index+1];
|
136 |
|
|
if(hwif->is_promise2) /* we've already been found ! */
|
137 |
|
|
return 1;
|
138 |
|
|
|
139 |
|
|
if(IN_BYTE(IDE_NSECTOR_REG) == 0xFF || IN_BYTE(IDE_SECTOR_REG) == 0xFF)
|
140 |
|
|
{
|
141 |
|
|
return 0;
|
142 |
|
|
}
|
143 |
|
|
OUT_BYTE(0x08,IDE_CONTROL_REG);
|
144 |
|
|
if(promise_cmd(drive,PROMISE_GET_CONFIG)) {
|
145 |
|
|
return 0;
|
146 |
|
|
}
|
147 |
|
|
if(ide_wait_stat(drive,DATA_READY,BAD_W_STAT,WAIT_DRQ)) {
|
148 |
|
|
printk("%s: Failed Promise read config!\n",hwif->name);
|
149 |
|
|
return 0;
|
150 |
|
|
}
|
151 |
|
|
ide_input_data(drive,&ident,SECTOR_WORDS);
|
152 |
|
|
if(ident.id[1] != 'P' || ident.id[0] != 'T') {
|
153 |
|
|
return 0;
|
154 |
|
|
}
|
155 |
|
|
printk("%s: Promise caching controller, ",hwif->name);
|
156 |
|
|
switch(ident.type) {
|
157 |
|
|
case 0x43: printk("DC4030VL-2, "); break;
|
158 |
|
|
case 0x41: printk("DC4030VL-1, "); break;
|
159 |
|
|
case 0x40: printk("DC4030VL, "); break;
|
160 |
|
|
default: printk("unknown - type 0x%02x - please report!\n"
|
161 |
|
|
,ident.type);
|
162 |
|
|
return 0;
|
163 |
|
|
}
|
164 |
|
|
printk("%dKB cache, ",(int)ident.cache_mem);
|
165 |
|
|
switch(ident.irq) {
|
166 |
|
|
case 0x00: hwif->irq = 14; break;
|
167 |
|
|
case 0x01: hwif->irq = 12; break;
|
168 |
|
|
default: hwif->irq = 15; break;
|
169 |
|
|
}
|
170 |
|
|
printk("on IRQ %d\n",hwif->irq);
|
171 |
|
|
hwif->chipset = second_hwif->chipset = ide_promise;
|
172 |
|
|
hwif->selectproc = second_hwif->selectproc = &promise_selectproc;
|
173 |
|
|
/* Shift the remaining interfaces down by one */
|
174 |
|
|
for (i=MAX_HWIFS-1 ; i > hwif->index+1 ; i--) {
|
175 |
|
|
printk("Shifting i/f %d values to i/f %d\n",i-1,i);
|
176 |
|
|
ide_hwifs[i].io_base = ide_hwifs[i-1].io_base;
|
177 |
|
|
ide_hwifs[i].ctl_port = ide_hwifs[i-1].ctl_port;
|
178 |
|
|
ide_hwifs[i].noprobe = ide_hwifs[i-1].noprobe;
|
179 |
|
|
}
|
180 |
|
|
second_hwif->is_promise2 = 1;
|
181 |
|
|
second_hwif->io_base = hwif->io_base;
|
182 |
|
|
second_hwif->ctl_port = hwif->ctl_port;
|
183 |
|
|
second_hwif->irq = hwif->irq;
|
184 |
|
|
for (i=0; i<2 ; i++) {
|
185 |
|
|
hwif->drives[i].io_32bit = 3;
|
186 |
|
|
second_hwif->drives[i].io_32bit = 3;
|
187 |
|
|
if(!ident.current_tm[i+2].cyl) second_hwif->drives[i].noprobe=1;
|
188 |
|
|
}
|
189 |
|
|
return 1;
|
190 |
|
|
}
|
191 |
|
|
|
192 |
|
|
/*
|
193 |
|
|
* promise_read_intr() is the handler for disk read/multread interrupts
|
194 |
|
|
*/
|
195 |
|
|
static void promise_read_intr (ide_drive_t *drive)
|
196 |
|
|
{
|
197 |
|
|
byte stat;
|
198 |
|
|
int i;
|
199 |
|
|
unsigned int sectors_left, sectors_avail, nsect;
|
200 |
|
|
struct request *rq;
|
201 |
|
|
|
202 |
|
|
if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
|
203 |
|
|
ide_error(drive, "promise_read_intr", stat);
|
204 |
|
|
return;
|
205 |
|
|
}
|
206 |
|
|
|
207 |
|
|
read_again:
|
208 |
|
|
do {
|
209 |
|
|
sectors_left = IN_BYTE(IDE_NSECTOR_REG);
|
210 |
|
|
IN_BYTE(IDE_SECTOR_REG);
|
211 |
|
|
} while (IN_BYTE(IDE_NSECTOR_REG) != sectors_left);
|
212 |
|
|
rq = HWGROUP(drive)->rq;
|
213 |
|
|
sectors_avail = rq->nr_sectors - sectors_left;
|
214 |
|
|
|
215 |
|
|
read_next:
|
216 |
|
|
rq = HWGROUP(drive)->rq;
|
217 |
|
|
if ((nsect = rq->current_nr_sectors) > sectors_avail)
|
218 |
|
|
nsect = sectors_avail;
|
219 |
|
|
sectors_avail -= nsect;
|
220 |
|
|
ide_input_data(drive, rq->buffer, nsect * SECTOR_WORDS);
|
221 |
|
|
#ifdef DEBUG
|
222 |
|
|
printk("%s: promise_read: sectors(%ld-%ld), buffer=0x%08lx, "
|
223 |
|
|
"remaining=%ld\n", drive->name, rq->sector, rq->sector+nsect-1,
|
224 |
|
|
(unsigned long) rq->buffer+(nsect<<9), rq->nr_sectors-nsect);
|
225 |
|
|
#endif
|
226 |
|
|
rq->sector += nsect;
|
227 |
|
|
rq->buffer += nsect<<9;
|
228 |
|
|
rq->errors = 0;
|
229 |
|
|
i = (rq->nr_sectors -= nsect);
|
230 |
|
|
if ((rq->current_nr_sectors -= nsect) <= 0)
|
231 |
|
|
ide_end_request(1, HWGROUP(drive));
|
232 |
|
|
if (i > 0) {
|
233 |
|
|
if (sectors_avail)
|
234 |
|
|
goto read_next;
|
235 |
|
|
stat = GET_STAT();
|
236 |
|
|
if(stat & DRQ_STAT)
|
237 |
|
|
goto read_again;
|
238 |
|
|
if(stat & BUSY_STAT) {
|
239 |
|
|
ide_set_handler (drive, &promise_read_intr, WAIT_CMD);
|
240 |
|
|
return;
|
241 |
|
|
}
|
242 |
|
|
printk("Ah! promise read intr: sectors left !DRQ !BUSY\n");
|
243 |
|
|
ide_error(drive, "promise read intr", stat);
|
244 |
|
|
}
|
245 |
|
|
}
|
246 |
|
|
|
247 |
|
|
/*
|
248 |
|
|
* promise_write_pollfunc() is the handler for disk write completion polling.
|
249 |
|
|
*/
|
250 |
|
|
static void promise_write_pollfunc (ide_drive_t *drive)
|
251 |
|
|
{
|
252 |
|
|
int i;
|
253 |
|
|
ide_hwgroup_t *hwgroup = HWGROUP(drive);
|
254 |
|
|
struct request *rq;
|
255 |
|
|
|
256 |
|
|
if (IN_BYTE(IDE_NSECTOR_REG) != 0) {
|
257 |
|
|
if (jiffies < hwgroup->poll_timeout) {
|
258 |
|
|
ide_set_handler (drive, &promise_write_pollfunc, 1);
|
259 |
|
|
return; /* continue polling... */
|
260 |
|
|
}
|
261 |
|
|
printk("%s: write timed-out!\n",drive->name);
|
262 |
|
|
ide_error (drive, "write timeout", GET_STAT());
|
263 |
|
|
return;
|
264 |
|
|
}
|
265 |
|
|
|
266 |
|
|
ide_multwrite(drive, 4);
|
267 |
|
|
rq = hwgroup->rq;
|
268 |
|
|
for (i = rq->nr_sectors; i > 0;) {
|
269 |
|
|
i -= rq->current_nr_sectors;
|
270 |
|
|
ide_end_request(1, hwgroup);
|
271 |
|
|
}
|
272 |
|
|
return;
|
273 |
|
|
}
|
274 |
|
|
|
275 |
|
|
/*
|
276 |
|
|
* promise_write() transfers a block of one or more sectors of data to a
|
277 |
|
|
* drive as part of a disk write operation. All but 4 sectors are transfered
|
278 |
|
|
* in the first attempt, then the interface is polled (nicely!) for completion
|
279 |
|
|
* before the final 4 sectors are transfered. Don't ask me why, but this is
|
280 |
|
|
* how it's done in the drivers for other O/Ses. There is no interrupt
|
281 |
|
|
* generated on writes, which is why we have to do it like this.
|
282 |
|
|
*/
|
283 |
|
|
static void promise_write (ide_drive_t *drive)
|
284 |
|
|
{
|
285 |
|
|
ide_hwgroup_t *hwgroup = HWGROUP(drive);
|
286 |
|
|
struct request *rq = &hwgroup->wrq;
|
287 |
|
|
int i;
|
288 |
|
|
|
289 |
|
|
if (rq->nr_sectors > 4) {
|
290 |
|
|
ide_multwrite(drive, rq->nr_sectors - 4);
|
291 |
|
|
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
|
292 |
|
|
ide_set_handler (drive, &promise_write_pollfunc, 1);
|
293 |
|
|
return;
|
294 |
|
|
} else {
|
295 |
|
|
ide_multwrite(drive, rq->nr_sectors);
|
296 |
|
|
rq = hwgroup->rq;
|
297 |
|
|
for (i = rq->nr_sectors; i > 0;) {
|
298 |
|
|
i -= rq->current_nr_sectors;
|
299 |
|
|
ide_end_request(1, hwgroup);
|
300 |
|
|
}
|
301 |
|
|
}
|
302 |
|
|
}
|
303 |
|
|
|
304 |
|
|
/*
|
305 |
|
|
* do_promise_io() is called from do_rw_disk, having had the block number
|
306 |
|
|
* already set up. It issues a READ or WRITE command to the Promise
|
307 |
|
|
* controller, assuming LBA has been used to set up the block number.
|
308 |
|
|
*/
|
309 |
|
|
void do_promise_io (ide_drive_t *drive, struct request *rq)
|
310 |
|
|
{
|
311 |
|
|
unsigned long timeout;
|
312 |
|
|
unsigned short io_base = HWIF(drive)->io_base;
|
313 |
|
|
byte stat;
|
314 |
|
|
|
315 |
|
|
if (rq->cmd == READ) {
|
316 |
|
|
ide_set_handler(drive, &promise_read_intr, WAIT_CMD);
|
317 |
|
|
OUT_BYTE(PROMISE_READ, io_base+IDE_COMMAND_OFFSET);
|
318 |
|
|
/* The card's behaviour is odd at this point. If the data is
|
319 |
|
|
available, DRQ will be true, and no interrupt will be
|
320 |
|
|
generated by the card. If this is the case, we need to simulate
|
321 |
|
|
an interrupt. Ugh! Otherwise, if an interrupt will occur, bit0
|
322 |
|
|
of the SELECT register will be high, so we can just return and
|
323 |
|
|
be interrupted.*/
|
324 |
|
|
timeout = jiffies + HZ/20; /* 50ms wait */
|
325 |
|
|
do {
|
326 |
|
|
stat=GET_STAT();
|
327 |
|
|
if(stat & DRQ_STAT) {
|
328 |
|
|
/* unsigned long flags;
|
329 |
|
|
save_flags(flags);
|
330 |
|
|
cli();
|
331 |
|
|
disable_irq(HWIF(drive)->irq);
|
332 |
|
|
*/
|
333 |
|
|
ide_intr(HWIF(drive)->irq,HWGROUP(drive),NULL);
|
334 |
|
|
/* enable_irq(HWIF(drive)->irq);
|
335 |
|
|
restore_flags(flags);
|
336 |
|
|
*/
|
337 |
|
|
return;
|
338 |
|
|
}
|
339 |
|
|
if(IN_BYTE(io_base+IDE_SELECT_OFFSET) & 0x01)
|
340 |
|
|
return;
|
341 |
|
|
udelay(1);
|
342 |
|
|
} while (jiffies < timeout);
|
343 |
|
|
printk("%s: reading: No DRQ and not waiting - Odd!\n",
|
344 |
|
|
drive->name);
|
345 |
|
|
return;
|
346 |
|
|
}
|
347 |
|
|
if (rq->cmd == WRITE) {
|
348 |
|
|
OUT_BYTE(PROMISE_WRITE, io_base+IDE_COMMAND_OFFSET);
|
349 |
|
|
if (ide_wait_stat(drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
|
350 |
|
|
printk("%s: no DRQ after issuing PROMISE_WRITE\n", drive->name);
|
351 |
|
|
return;
|
352 |
|
|
}
|
353 |
|
|
if (!drive->unmask)
|
354 |
|
|
cli();
|
355 |
|
|
HWGROUP(drive)->wrq = *rq; /* scratchpad */
|
356 |
|
|
promise_write(drive);
|
357 |
|
|
return;
|
358 |
|
|
}
|
359 |
|
|
printk("%s: bad command: %d\n", drive->name, rq->cmd);
|
360 |
|
|
ide_end_request(0, HWGROUP(drive));
|
361 |
|
|
}
|