Blame view
drivers/ide/ide-taskfile.c
16.6 KB
1da177e4c Linux-2.6.12-rc2 |
1 |
/* |
59bca8cc9 ide: update/add m... |
2 3 4 |
* Copyright (C) 2000-2002 Michael Cornwell <cornwell@acm.org> * Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org> * Copyright (C) 2001-2002 Klaus Smolin |
1da177e4c Linux-2.6.12-rc2 |
5 |
* IBM Storage Technology Division |
59bca8cc9 ide: update/add m... |
6 |
* Copyright (C) 2003-2004, 2007 Bartlomiej Zolnierkiewicz |
1da177e4c Linux-2.6.12-rc2 |
7 8 |
* * The big the bad and the ugly. |
1da177e4c Linux-2.6.12-rc2 |
9 |
*/ |
1da177e4c Linux-2.6.12-rc2 |
10 11 12 |
#include <linux/types.h> #include <linux/string.h> #include <linux/kernel.h> |
38789fda2 ide/ata: Add expo... |
13 |
#include <linux/export.h> |
651c29a17 [PATCH] ide: touc... |
14 |
#include <linux/sched.h> |
1da177e4c Linux-2.6.12-rc2 |
15 |
#include <linux/interrupt.h> |
1da177e4c Linux-2.6.12-rc2 |
16 |
#include <linux/errno.h> |
1da177e4c Linux-2.6.12-rc2 |
17 |
#include <linux/slab.h> |
1da177e4c Linux-2.6.12-rc2 |
18 19 20 |
#include <linux/delay.h> #include <linux/hdreg.h> #include <linux/ide.h> |
55c16a700 IDE: sg chaining ... |
21 |
#include <linux/scatterlist.h> |
2d5abcede ide: ide-taskfile... |
22 |
#include <linux/uaccess.h> |
1da177e4c Linux-2.6.12-rc2 |
23 |
|
1da177e4c Linux-2.6.12-rc2 |
24 |
#include <asm/io.h> |
3153c26b5 ide: refactor tf_... |
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
void ide_tf_readback(ide_drive_t *drive, struct ide_cmd *cmd) { ide_hwif_t *hwif = drive->hwif; const struct ide_tp_ops *tp_ops = hwif->tp_ops; /* Be sure we're looking at the low order bytes */ tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS); tp_ops->tf_read(drive, &cmd->tf, cmd->valid.in.tf); if (cmd->tf_flags & IDE_TFLAG_LBA48) { tp_ops->write_devctl(hwif, ATA_HOB | ATA_DEVCTL_OBS); tp_ops->tf_read(drive, &cmd->hob, cmd->valid.in.hob); } } |
745483f10 ide: simplify 'st... |
41 |
void ide_tf_dump(const char *s, struct ide_cmd *cmd) |
9e42237f2 ide: add ide_tf_l... |
42 |
{ |
807e35d69 ide: use ide_tf_l... |
43 44 45 46 |
#ifdef DEBUG printk("%s: tf: feat 0x%02x nsect 0x%02x lbal 0x%02x " "lbam 0x%02x lbah 0x%02x dev 0x%02x cmd 0x%02x ", |
745483f10 ide: simplify 'st... |
47 48 49 50 51 52 |
s, cmd->tf.feature, cmd->tf.nsect, cmd->tf.lbal, cmd->tf.lbam, cmd->tf.lbah, cmd->tf.device, cmd->tf.command); printk("%s: hob: nsect 0x%02x lbal 0x%02x lbam 0x%02x lbah 0x%02x ", s, cmd->hob.nsect, cmd->hob.lbal, cmd->hob.lbam, cmd->hob.lbah); |
807e35d69 ide: use ide_tf_l... |
53 |
#endif |
089c5c7e0 ide: factor out d... |
54 |
} |
2d5abcede ide: ide-taskfile... |
55 |
int taskfile_lib_get_identify(ide_drive_t *drive, u8 *buf) |
1da177e4c Linux-2.6.12-rc2 |
56 |
{ |
22aa4b32a ide: remove ide_t... |
57 |
struct ide_cmd cmd; |
650d841d9 ide: add struct i... |
58 |
|
22aa4b32a ide: remove ide_t... |
59 60 |
memset(&cmd, 0, sizeof(cmd)); cmd.tf.nsect = 0x01; |
1da177e4c Linux-2.6.12-rc2 |
61 |
if (drive->media == ide_disk) |
22aa4b32a ide: remove ide_t... |
62 |
cmd.tf.command = ATA_CMD_ID_ATA; |
1da177e4c Linux-2.6.12-rc2 |
63 |
else |
22aa4b32a ide: remove ide_t... |
64 |
cmd.tf.command = ATA_CMD_ID_ATAPI; |
60f85019c ide: replace IDE_... |
65 66 |
cmd.valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; cmd.valid.in.tf = IDE_VALID_IN_TF | IDE_VALID_DEVICE; |
0dfb991c6 ide: use ata_tf_p... |
67 |
cmd.protocol = ATA_PROT_PIO; |
22aa4b32a ide: remove ide_t... |
68 69 |
return ide_raw_taskfile(drive, &cmd, buf, 1); |
1da177e4c Linux-2.6.12-rc2 |
70 |
} |
1192e528e ide: use ->data_p... |
71 |
static ide_startstop_t task_no_data_intr(ide_drive_t *); |
adb1af980 ide: pass command... |
72 |
static ide_startstop_t pre_task_out_intr(ide_drive_t *, struct ide_cmd *); |
901bd08a5 ide: merge task_{... |
73 |
static ide_startstop_t task_pio_intr(ide_drive_t *); |
1192e528e ide: use ->data_p... |
74 |
|
adb1af980 ide: pass command... |
75 |
ide_startstop_t do_rw_taskfile(ide_drive_t *drive, struct ide_cmd *orig_cmd) |
1da177e4c Linux-2.6.12-rc2 |
76 |
{ |
898ec223f ide: remove HWIF(... |
77 |
ide_hwif_t *hwif = drive->hwif; |
adb1af980 ide: pass command... |
78 |
struct ide_cmd *cmd = &hwif->cmd; |
22aa4b32a ide: remove ide_t... |
79 |
struct ide_taskfile *tf = &cmd->tf; |
57d7366b7 ide: remove 'hand... |
80 |
ide_handler_t *handler = NULL; |
374e042c3 ide: add struct i... |
81 |
const struct ide_tp_ops *tp_ops = hwif->tp_ops; |
f37afdaca ide: constify str... |
82 |
const struct ide_dma_ops *dma_ops = hwif->dma_ops; |
1da177e4c Linux-2.6.12-rc2 |
83 |
|
0dfb991c6 ide: use ata_tf_p... |
84 85 86 |
if (orig_cmd->protocol == ATA_PROT_PIO && (orig_cmd->tf_flags & IDE_TFLAG_MULTI_PIO) && drive->mult_count == 0) { |
2d5abcede ide: ide-taskfile... |
87 88 |
pr_err("%s: multimode not set! ", drive->name); |
0dfb991c6 ide: use ata_tf_p... |
89 |
return ide_stopped; |
1edee60e9 ide: merge flagge... |
90 |
} |
adb1af980 ide: pass command... |
91 92 |
if (orig_cmd->ftf_flags & IDE_FTFLAG_FLAGGED) orig_cmd->ftf_flags |= IDE_FTFLAG_SET_IN_FLAGS; |
1edee60e9 ide: merge flagge... |
93 |
|
adb1af980 ide: pass command... |
94 |
memcpy(cmd, orig_cmd, sizeof(*cmd)); |
d6ff9f64e ide: merge all TA... |
95 |
|
22aa4b32a ide: remove ide_t... |
96 |
if ((cmd->tf_flags & IDE_TFLAG_DMA_PIO_FALLBACK) == 0) { |
745483f10 ide: simplify 'st... |
97 |
ide_tf_dump(drive->name, cmd); |
ecf3a31d2 ide: turn set_irq... |
98 |
tp_ops->write_devctl(hwif, ATA_DEVCTL_OBS); |
35218d1ca ide: move data re... |
99 100 |
if (cmd->ftf_flags & IDE_FTFLAG_OUT_DATA) { |
745483f10 ide: simplify 'st... |
101 |
u8 data[2] = { cmd->tf.data, cmd->hob.data }; |
35218d1ca ide: move data re... |
102 103 104 |
tp_ops->output_data(drive, cmd, data, 2); } |
4109d19af ide: move common ... |
105 106 107 108 109 110 111 112 113 |
if (cmd->valid.out.tf & IDE_VALID_DEVICE) { u8 HIHI = (cmd->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF; if (!(cmd->ftf_flags & IDE_FTFLAG_FLAGGED)) cmd->tf.device &= HIHI; cmd->tf.device |= drive->select; } |
c9ff9e7b6 ide: refactor tf_... |
114 115 |
tp_ops->tf_load(drive, &cmd->hob, cmd->valid.out.hob); tp_ops->tf_load(drive, &cmd->tf, cmd->valid.out.tf); |
089c5c7e0 ide: factor out d... |
116 |
} |
1da177e4c Linux-2.6.12-rc2 |
117 |
|
0dfb991c6 ide: use ata_tf_p... |
118 119 120 121 122 123 124 |
switch (cmd->protocol) { case ATA_PROT_PIO: if (cmd->tf_flags & IDE_TFLAG_WRITE) { tp_ops->exec_command(hwif, tf->command); ndelay(400); /* FIXME */ return pre_task_out_intr(drive, cmd); } |
901bd08a5 ide: merge task_{... |
125 |
handler = task_pio_intr; |
1192e528e ide: use ->data_p... |
126 |
/* fall-through */ |
0dfb991c6 ide: use ata_tf_p... |
127 |
case ATA_PROT_NODATA: |
57d7366b7 ide: remove 'hand... |
128 129 |
if (handler == NULL) handler = task_no_data_intr; |
35b5d0be3 ide: remove ide_e... |
130 |
ide_execute_command(drive, cmd, handler, WAIT_WORSTCASE); |
1da177e4c Linux-2.6.12-rc2 |
131 |
return ide_started; |
b788ee9c6 ide: use do_rw_ta... |
132 |
case ATA_PROT_DMA: |
5ae5412d9 ide: add ide_dma_... |
133 |
if (ide_dma_prepare(drive, cmd)) |
10d90157c ide: convert do_r... |
134 |
return ide_stopped; |
22117d6ea ide: add ->dma_ti... |
135 |
hwif->expiry = dma_ops->dma_timer_expiry; |
35b5d0be3 ide: remove ide_e... |
136 |
ide_execute_command(drive, cmd, ide_dma_intr, 2 * WAIT_CMD); |
5e37bdc08 ide: add struct i... |
137 |
dma_ops->dma_start(drive); |
b788ee9c6 ide: use do_rw_ta... |
138 |
default: |
74095a91e ide: use do_rw_ta... |
139 |
return ide_started; |
1da177e4c Linux-2.6.12-rc2 |
140 |
} |
1da177e4c Linux-2.6.12-rc2 |
141 |
} |
f6e29e35c ide-disk: use do_... |
142 |
EXPORT_SYMBOL_GPL(do_rw_taskfile); |
1da177e4c Linux-2.6.12-rc2 |
143 |
|
d6ff9f64e ide: merge all TA... |
144 |
static ide_startstop_t task_no_data_intr(ide_drive_t *drive) |
1da177e4c Linux-2.6.12-rc2 |
145 |
{ |
b73c7ee25 ide: add ->read_s... |
146 |
ide_hwif_t *hwif = drive->hwif; |
22aa4b32a ide: remove ide_t... |
147 148 149 |
struct ide_cmd *cmd = &hwif->cmd; struct ide_taskfile *tf = &cmd->tf; int custom = (cmd->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) ? 1 : 0; |
d6ff9f64e ide: merge all TA... |
150 |
int retries = (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) ? 5 : 1; |
1da177e4c Linux-2.6.12-rc2 |
151 |
u8 stat; |
90d2c6bc6 ide: enable local... |
152 |
local_irq_enable_in_hardirq(); |
374e042c3 ide: add struct i... |
153 154 |
while (1) { stat = hwif->tp_ops->read_status(hwif); |
3a7d24841 ide: use ATA_* de... |
155 |
if ((stat & ATA_BUSY) == 0 || retries-- == 0) |
374e042c3 ide: add struct i... |
156 |
break; |
1da177e4c Linux-2.6.12-rc2 |
157 |
udelay(10); |
374e042c3 ide: add struct i... |
158 |
}; |
1da177e4c Linux-2.6.12-rc2 |
159 |
|
d6ff9f64e ide: merge all TA... |
160 161 162 |
if (!OK_STAT(stat, ATA_DRDY, BAD_STAT)) { if (custom && tf->command == ATA_CMD_SET_MULTI) { drive->mult_req = drive->mult_count = 0; |
ca1b96e00 ide: replace spec... |
163 |
drive->special_flags |= IDE_SFLAG_RECALIBRATE; |
d6ff9f64e ide: merge all TA... |
164 165 166 167 168 |
(void)ide_dump_status(drive, __func__, stat); return ide_stopped; } else if (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) { if ((stat & (ATA_ERR | ATA_DRQ)) == 0) { ide_set_handler(drive, &task_no_data_intr, |
60c0cd02b ide: set hwif->ex... |
169 |
WAIT_WORSTCASE); |
d6ff9f64e ide: merge all TA... |
170 171 172 |
return ide_started; } } |
1da177e4c Linux-2.6.12-rc2 |
173 |
return ide_error(drive, "task_no_data_intr", stat); |
d6ff9f64e ide: merge all TA... |
174 |
} |
c47137a99 ide: add ide_read... |
175 |
|
e7fedc3ca ide: use ide_comp... |
176 |
if (custom && tf->command == ATA_CMD_SET_MULTI) |
d6ff9f64e ide: merge all TA... |
177 |
drive->mult_count = drive->mult_req; |
1da177e4c Linux-2.6.12-rc2 |
178 |
|
d364c7f50 ide: use ide_comp... |
179 180 |
if (custom == 0 || tf->command == ATA_CMD_IDLEIMMEDIATE || tf->command == ATA_CMD_CHK_POWER) { |
a09485df9 ide: move request... |
181 |
struct request *rq = hwif->rq; |
a09485df9 ide: move request... |
182 183 184 |
if (blk_pm_request(rq)) ide_complete_pm_rq(drive, rq); |
2230d90dd ide: sanitize ide... |
185 186 |
else ide_finish_cmd(drive, cmd, stat); |
a09485df9 ide: move request... |
187 |
} |
1da177e4c Linux-2.6.12-rc2 |
188 189 |
return ide_stopped; } |
da6f4c7f6 ide: make wait_dr... |
190 |
static u8 wait_drive_not_busy(ide_drive_t *drive) |
1da177e4c Linux-2.6.12-rc2 |
191 |
{ |
b73c7ee25 ide: add ->read_s... |
192 |
ide_hwif_t *hwif = drive->hwif; |
b42fa1331 ide: never called... |
193 |
int retries; |
1da177e4c Linux-2.6.12-rc2 |
194 195 196 |
u8 stat; /* |
25985edce Fix common misspe... |
197 |
* Last sector was transferred, wait until device is ready. This can |
f54feafa6 ide: increase tim... |
198 |
* take up to 6 ms on some ATAPI devices, so we will wait max 10 ms. |
1da177e4c Linux-2.6.12-rc2 |
199 |
*/ |
f54feafa6 ide: increase tim... |
200 |
for (retries = 0; retries < 1000; retries++) { |
374e042c3 ide: add struct i... |
201 |
stat = hwif->tp_ops->read_status(hwif); |
c47137a99 ide: add ide_read... |
202 |
|
3a7d24841 ide: use ATA_* de... |
203 |
if (stat & ATA_BUSY) |
b42fa1331 ide: never called... |
204 205 206 207 |
udelay(10); else break; } |
1da177e4c Linux-2.6.12-rc2 |
208 |
|
3a7d24841 ide: use ATA_* de... |
209 |
if (stat & ATA_BUSY) |
2d5abcede ide: ide-taskfile... |
210 211 |
pr_err("%s: drive still BUSY! ", drive->name); |
1da177e4c Linux-2.6.12-rc2 |
212 213 214 |
return stat; } |
a08915ba5 ide-cd: use scatt... |
215 216 |
void ide_pio_bytes(ide_drive_t *drive, struct ide_cmd *cmd, unsigned int write, unsigned int len) |
1da177e4c Linux-2.6.12-rc2 |
217 218 219 |
{ ide_hwif_t *hwif = drive->hwif; struct scatterlist *sg = hwif->sg_table; |
b6308ee0c ide: move command... |
220 |
struct scatterlist *cursg = cmd->cursg; |
7fa350b47 ide: Fix annoying... |
221 |
unsigned long uninitialized_var(flags); |
1da177e4c Linux-2.6.12-rc2 |
222 |
struct page *page; |
1da177e4c Linux-2.6.12-rc2 |
223 224 |
unsigned int offset; u8 *buf; |
b6308ee0c ide: move command... |
225 |
cursg = cmd->cursg; |
7a00798b1 ide: add support ... |
226 227 228 229 230 |
if (cursg == NULL) cursg = cmd->cursg = sg; while (len) { unsigned nr_bytes = min(len, cursg->length - cmd->cursg_ofs); |
a90790521 IDE: Save a call ... |
231 |
int page_is_high; |
55c16a700 IDE: sg chaining ... |
232 |
|
7a00798b1 ide: add support ... |
233 234 |
if (nr_bytes > PAGE_SIZE) nr_bytes = PAGE_SIZE; |
1da177e4c Linux-2.6.12-rc2 |
235 |
|
7a00798b1 ide: add support ... |
236 237 238 239 240 241 |
page = sg_page(cursg); offset = cursg->offset + cmd->cursg_ofs; /* get the current page and offset */ page = nth_page(page, (offset >> PAGE_SHIFT)); offset %= PAGE_SIZE; |
1da177e4c Linux-2.6.12-rc2 |
242 |
|
a90790521 IDE: Save a call ... |
243 244 |
page_is_high = PageHighMem(page); if (page_is_high) |
f2bc31673 ide: use PageHigh... |
245 |
local_irq_save(flags); |
7a00798b1 ide: add support ... |
246 |
buf = kmap_atomic(page, KM_BIO_SRC_IRQ) + offset; |
1da177e4c Linux-2.6.12-rc2 |
247 |
|
7a00798b1 ide: add support ... |
248 249 |
cmd->nleft -= nr_bytes; cmd->cursg_ofs += nr_bytes; |
1da177e4c Linux-2.6.12-rc2 |
250 |
|
7a00798b1 ide: add support ... |
251 252 253 254 |
if (cmd->cursg_ofs == cursg->length) { cursg = cmd->cursg = sg_next(cmd->cursg); cmd->cursg_ofs = 0; } |
1da177e4c Linux-2.6.12-rc2 |
255 |
|
7a00798b1 ide: add support ... |
256 257 258 259 260 |
/* do the actual data transfer */ if (write) hwif->tp_ops->output_data(drive, cmd, buf, nr_bytes); else hwif->tp_ops->input_data(drive, cmd, buf, nr_bytes); |
1da177e4c Linux-2.6.12-rc2 |
261 |
|
7a00798b1 ide: add support ... |
262 |
kunmap_atomic(buf, KM_BIO_SRC_IRQ); |
f2bc31673 ide: use PageHigh... |
263 |
|
a90790521 IDE: Save a call ... |
264 |
if (page_is_high) |
f2bc31673 ide: use PageHigh... |
265 |
local_irq_restore(flags); |
1da177e4c Linux-2.6.12-rc2 |
266 |
|
7a00798b1 ide: add support ... |
267 268 |
len -= nr_bytes; } |
1da177e4c Linux-2.6.12-rc2 |
269 |
} |
a08915ba5 ide-cd: use scatt... |
270 |
EXPORT_SYMBOL_GPL(ide_pio_bytes); |
1da177e4c Linux-2.6.12-rc2 |
271 |
|
adb1af980 ide: pass command... |
272 273 |
static void ide_pio_datablock(ide_drive_t *drive, struct ide_cmd *cmd, unsigned int write) |
1da177e4c Linux-2.6.12-rc2 |
274 |
{ |
7a00798b1 ide: add support ... |
275 |
unsigned int nr_bytes; |
35cf2b94d ide: fix ->io_32b... |
276 |
u8 saved_io_32bit = drive->io_32bit; |
adb1af980 ide: pass command... |
277 278 |
if (cmd->tf_flags & IDE_TFLAG_FS) cmd->rq->errors = 0; |
1da177e4c Linux-2.6.12-rc2 |
279 |
|
22aa4b32a ide: remove ide_t... |
280 |
if (cmd->tf_flags & IDE_TFLAG_IO_16BIT) |
e3d9a73a8 ide: remove ->dat... |
281 |
drive->io_32bit = 0; |
35cf2b94d ide: fix ->io_32b... |
282 |
|
651c29a17 [PATCH] ide: touc... |
283 |
touch_softlockup_watchdog(); |
0dfb991c6 ide: use ata_tf_p... |
284 |
if (cmd->tf_flags & IDE_TFLAG_MULTI_PIO) |
7a00798b1 ide: add support ... |
285 |
nr_bytes = min_t(unsigned, cmd->nleft, drive->mult_count << 9); |
0dfb991c6 ide: use ata_tf_p... |
286 |
else |
7a00798b1 ide: add support ... |
287 288 289 |
nr_bytes = SECTOR_SIZE; ide_pio_bytes(drive, cmd, write, nr_bytes); |
35cf2b94d ide: fix ->io_32b... |
290 291 |
drive->io_32bit = saved_io_32bit; |
1da177e4c Linux-2.6.12-rc2 |
292 |
} |
041cea10a ide: task_error()... |
293 |
static void ide_error_cmd(ide_drive_t *drive, struct ide_cmd *cmd) |
1da177e4c Linux-2.6.12-rc2 |
294 |
{ |
adb1af980 ide: pass command... |
295 |
if (cmd->tf_flags & IDE_TFLAG_FS) { |
bf717c0a2 ide: keep track o... |
296 |
int nr_bytes = cmd->nbytes - cmd->nleft; |
1da177e4c Linux-2.6.12-rc2 |
297 |
|
0dfb991c6 ide: use ata_tf_p... |
298 299 300 |
if (cmd->protocol == ATA_PROT_PIO && ((cmd->tf_flags & IDE_TFLAG_WRITE) || cmd->nleft == 0)) { if (cmd->tf_flags & IDE_TFLAG_MULTI_PIO) |
bf717c0a2 ide: keep track o... |
301 |
nr_bytes -= drive->mult_count << 9; |
0dfb991c6 ide: use ata_tf_p... |
302 |
else |
bf717c0a2 ide: keep track o... |
303 |
nr_bytes -= SECTOR_SIZE; |
1da177e4c Linux-2.6.12-rc2 |
304 |
} |
bf717c0a2 ide: keep track o... |
305 306 |
if (nr_bytes > 0) ide_complete_rq(drive, 0, nr_bytes); |
1da177e4c Linux-2.6.12-rc2 |
307 |
} |
1da177e4c Linux-2.6.12-rc2 |
308 |
} |
adb1af980 ide: pass command... |
309 |
void ide_finish_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat) |
1da177e4c Linux-2.6.12-rc2 |
310 |
{ |
6902a5331 ide: pass error v... |
311 |
struct request *rq = drive->hwif->rq; |
665d66e8f ide: fix races in... |
312 313 |
u8 err = ide_read_error(drive), nsect = cmd->tf.nsect; u8 set_xfer = !!(cmd->tf_flags & IDE_TFLAG_SET_XFER); |
1da177e4c Linux-2.6.12-rc2 |
314 |
|
2230d90dd ide: sanitize ide... |
315 |
ide_complete_cmd(drive, cmd, stat, err); |
6902a5331 ide: pass error v... |
316 |
rq->errors = err; |
665d66e8f ide: fix races in... |
317 318 319 320 321 |
if (err == 0 && set_xfer) { ide_set_xfer_rate(drive, nsect); ide_driveid_update(drive); } |
f974b196f ide: pass number ... |
322 |
ide_complete_rq(drive, err ? -EIO : 0, blk_rq_bytes(rq)); |
1da177e4c Linux-2.6.12-rc2 |
323 324 325 |
} /* |
901bd08a5 ide: merge task_{... |
326 |
* Handler for command with PIO data phase. |
1da177e4c Linux-2.6.12-rc2 |
327 |
*/ |
901bd08a5 ide: merge task_{... |
328 |
static ide_startstop_t task_pio_intr(ide_drive_t *drive) |
1da177e4c Linux-2.6.12-rc2 |
329 330 |
{ ide_hwif_t *hwif = drive->hwif; |
adb1af980 ide: pass command... |
331 |
struct ide_cmd *cmd = &drive->hwif->cmd; |
374e042c3 ide: add struct i... |
332 |
u8 stat = hwif->tp_ops->read_status(hwif); |
901bd08a5 ide: merge task_{... |
333 |
u8 write = !!(cmd->tf_flags & IDE_TFLAG_WRITE); |
1da177e4c Linux-2.6.12-rc2 |
334 |
|
901bd08a5 ide: merge task_{... |
335 336 337 |
if (write == 0) { /* Error? */ if (stat & ATA_ERR) |
0a1248c5a ide: unify exit p... |
338 |
goto out_err; |
1da177e4c Linux-2.6.12-rc2 |
339 |
|
901bd08a5 ide: merge task_{... |
340 |
/* Didn't want any data? Odd. */ |
151055ed8 ide: inline task_... |
341 342 |
if ((stat & ATA_DRQ) == 0) { /* Command all done? */ |
0a1248c5a ide: unify exit p... |
343 344 |
if (OK_STAT(stat, ATA_DRDY, ATA_BUSY)) goto out_end; |
151055ed8 ide: inline task_... |
345 346 |
/* Assume it was a spurious irq */ |
0a1248c5a ide: unify exit p... |
347 |
goto out_wait; |
151055ed8 ide: inline task_... |
348 |
} |
901bd08a5 ide: merge task_{... |
349 350 |
} else { if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat)) |
0a1248c5a ide: unify exit p... |
351 |
goto out_err; |
1da177e4c Linux-2.6.12-rc2 |
352 |
|
901bd08a5 ide: merge task_{... |
353 354 |
/* Deal with unexpected ATA data phase. */ if (((stat & ATA_DRQ) == 0) ^ (cmd->nleft == 0)) |
0a1248c5a ide: unify exit p... |
355 |
goto out_err; |
901bd08a5 ide: merge task_{... |
356 |
} |
0a1248c5a ide: unify exit p... |
357 358 |
if (write && cmd->nleft == 0) goto out_end; |
1da177e4c Linux-2.6.12-rc2 |
359 360 |
/* Still data left to transfer. */ |
901bd08a5 ide: merge task_{... |
361 |
ide_pio_datablock(drive, cmd, write); |
1da177e4c Linux-2.6.12-rc2 |
362 |
|
901bd08a5 ide: merge task_{... |
363 364 365 366 |
/* Are we done? Check status and finish transfer. */ if (write == 0 && cmd->nleft == 0) { stat = wait_drive_not_busy(drive); if (!OK_STAT(stat, 0, BAD_STAT)) |
0a1248c5a ide: unify exit p... |
367 |
goto out_err; |
1da177e4c Linux-2.6.12-rc2 |
368 |
|
0a1248c5a ide: unify exit p... |
369 370 371 |
goto out_end; } out_wait: |
1da177e4c Linux-2.6.12-rc2 |
372 |
/* Still data left to transfer. */ |
60c0cd02b ide: set hwif->ex... |
373 |
ide_set_handler(drive, &task_pio_intr, WAIT_WORSTCASE); |
1da177e4c Linux-2.6.12-rc2 |
374 |
return ide_started; |
0a1248c5a ide: unify exit p... |
375 |
out_end: |
2230d90dd ide: sanitize ide... |
376 377 378 |
if ((cmd->tf_flags & IDE_TFLAG_FS) == 0) ide_finish_cmd(drive, cmd, stat); else |
9780e2dd8 ide: convert to r... |
379 |
ide_complete_rq(drive, 0, blk_rq_sectors(cmd->rq) << 9); |
0a1248c5a ide: unify exit p... |
380 381 |
return ide_stopped; out_err: |
041cea10a ide: task_error()... |
382 383 |
ide_error_cmd(drive, cmd); return ide_error(drive, __func__, stat); |
1da177e4c Linux-2.6.12-rc2 |
384 |
} |
adb1af980 ide: pass command... |
385 386 |
static ide_startstop_t pre_task_out_intr(ide_drive_t *drive, struct ide_cmd *cmd) |
1da177e4c Linux-2.6.12-rc2 |
387 388 |
{ ide_startstop_t startstop; |
3a7d24841 ide: use ATA_* de... |
389 |
if (ide_wait_stat(&startstop, drive, ATA_DRQ, |
1da177e4c Linux-2.6.12-rc2 |
390 |
drive->bad_wstat, WAIT_DRQ)) { |
2d5abcede ide: ide-taskfile... |
391 392 |
pr_err("%s: no DRQ after issuing %sWRITE%s ", drive->name, |
0dfb991c6 ide: use ata_tf_p... |
393 |
(cmd->tf_flags & IDE_TFLAG_MULTI_PIO) ? "MULT" : "", |
97100fc81 ide: add device f... |
394 |
(drive->dev_flags & IDE_DFLAG_LBA48) ? "_EXT" : ""); |
1da177e4c Linux-2.6.12-rc2 |
395 396 |
return startstop; } |
97100fc81 ide: add device f... |
397 |
if ((drive->dev_flags & IDE_DFLAG_UNMASK) == 0) |
1da177e4c Linux-2.6.12-rc2 |
398 |
local_irq_disable(); |
60c0cd02b ide: set hwif->ex... |
399 |
ide_set_handler(drive, &task_pio_intr, WAIT_WORSTCASE); |
901bd08a5 ide: merge task_{... |
400 |
|
adb1af980 ide: pass command... |
401 |
ide_pio_datablock(drive, cmd, 1); |
1da177e4c Linux-2.6.12-rc2 |
402 403 404 |
return ide_started; } |
1da177e4c Linux-2.6.12-rc2 |
405 |
|
22aa4b32a ide: remove ide_t... |
406 407 |
int ide_raw_taskfile(ide_drive_t *drive, struct ide_cmd *cmd, u8 *buf, u16 nsect) |
1da177e4c Linux-2.6.12-rc2 |
408 |
{ |
154ed280e ide-taskfile: con... |
409 410 |
struct request *rq; int error; |
720fc22a7 ide: Fix IDE task... |
411 |
int rw = !(cmd->tf_flags & IDE_TFLAG_WRITE) ? READ : WRITE; |
1da177e4c Linux-2.6.12-rc2 |
412 |
|
720fc22a7 ide: Fix IDE task... |
413 |
rq = blk_get_request(drive->queue, rw, __GFP_WAIT); |
154ed280e ide-taskfile: con... |
414 |
rq->cmd_type = REQ_TYPE_ATA_TASKFILE; |
d868ca243 ide-taskfile: don... |
415 |
|
1da177e4c Linux-2.6.12-rc2 |
416 417 418 419 420 421 |
/* * (ks) We transfer currently only whole sectors. * This is suffient for now. But, it would be great, * if we would find a solution to transfer any size. * To support special commands like READ LONG. */ |
d868ca243 ide-taskfile: don... |
422 423 424 425 426 427 |
if (nsect) { error = blk_rq_map_kern(drive->queue, rq, buf, nsect * SECTOR_SIZE, __GFP_WAIT); if (error) goto put_req; } |
1da177e4c Linux-2.6.12-rc2 |
428 |
|
22aa4b32a ide: remove ide_t... |
429 430 |
rq->special = cmd; cmd->rq = rq; |
1da177e4c Linux-2.6.12-rc2 |
431 |
|
154ed280e ide-taskfile: con... |
432 |
error = blk_execute_rq(drive->queue, NULL, rq, 0); |
154ed280e ide-taskfile: con... |
433 |
|
d868ca243 ide-taskfile: don... |
434 435 |
put_req: blk_put_request(rq); |
154ed280e ide-taskfile: con... |
436 |
return error; |
1da177e4c Linux-2.6.12-rc2 |
437 |
} |
1da177e4c Linux-2.6.12-rc2 |
438 |
EXPORT_SYMBOL(ide_raw_taskfile); |
22aa4b32a ide: remove ide_t... |
439 |
int ide_no_data_taskfile(ide_drive_t *drive, struct ide_cmd *cmd) |
9a3c49be5 ide: add ide_no_d... |
440 |
{ |
0dfb991c6 ide: use ata_tf_p... |
441 |
cmd->protocol = ATA_PROT_NODATA; |
9a3c49be5 ide: add ide_no_d... |
442 |
|
22aa4b32a ide: remove ide_t... |
443 |
return ide_raw_taskfile(drive, cmd, NULL, 0); |
9a3c49be5 ide: add ide_no_d... |
444 445 |
} EXPORT_SYMBOL_GPL(ide_no_data_taskfile); |
26a5b0407 ide: add missing ... |
446 |
#ifdef CONFIG_IDE_TASK_IOCTL |
22aa4b32a ide: remove ide_t... |
447 |
int ide_taskfile_ioctl(ide_drive_t *drive, unsigned long arg) |
1da177e4c Linux-2.6.12-rc2 |
448 449 |
{ ide_task_request_t *req_task; |
22aa4b32a ide: remove ide_t... |
450 |
struct ide_cmd cmd; |
1da177e4c Linux-2.6.12-rc2 |
451 452 |
u8 *outbuf = NULL; u8 *inbuf = NULL; |
ac026ff25 ide: remove 'comm... |
453 |
u8 *data_buf = NULL; |
1da177e4c Linux-2.6.12-rc2 |
454 455 |
int err = 0; int tasksize = sizeof(struct ide_task_request_s); |
3a42bb223 [PATCH] ide: add ... |
456 457 |
unsigned int taskin = 0; unsigned int taskout = 0; |
ac026ff25 ide: remove 'comm... |
458 |
u16 nsect = 0; |
1da177e4c Linux-2.6.12-rc2 |
459 |
char __user *buf = (char __user *)arg; |
7d543d846 drivers/ide: Use ... |
460 461 462 |
req_task = memdup_user(buf, tasksize); if (IS_ERR(req_task)) return PTR_ERR(req_task); |
1da177e4c Linux-2.6.12-rc2 |
463 |
|
3a42bb223 [PATCH] ide: add ... |
464 465 |
taskout = req_task->out_size; taskin = req_task->in_size; |
2d5abcede ide: ide-taskfile... |
466 |
|
3a42bb223 [PATCH] ide: add ... |
467 468 469 470 |
if (taskin > 65536 || taskout > 65536) { err = -EINVAL; goto abort; } |
1da177e4c Linux-2.6.12-rc2 |
471 472 473 |
if (taskout) { int outtotal = tasksize; |
f5e3c2faa [PATCH] ide: kmal... |
474 |
outbuf = kzalloc(taskout, GFP_KERNEL); |
1da177e4c Linux-2.6.12-rc2 |
475 476 477 478 |
if (outbuf == NULL) { err = -ENOMEM; goto abort; } |
1da177e4c Linux-2.6.12-rc2 |
479 480 481 482 483 484 485 486 |
if (copy_from_user(outbuf, buf + outtotal, taskout)) { err = -EFAULT; goto abort; } } if (taskin) { int intotal = tasksize + taskout; |
f5e3c2faa [PATCH] ide: kmal... |
487 |
inbuf = kzalloc(taskin, GFP_KERNEL); |
1da177e4c Linux-2.6.12-rc2 |
488 489 490 491 |
if (inbuf == NULL) { err = -ENOMEM; goto abort; } |
1da177e4c Linux-2.6.12-rc2 |
492 493 494 495 496 |
if (copy_from_user(inbuf, buf + intotal, taskin)) { err = -EFAULT; goto abort; } } |
22aa4b32a ide: remove ide_t... |
497 |
memset(&cmd, 0, sizeof(cmd)); |
1da177e4c Linux-2.6.12-rc2 |
498 |
|
745483f10 ide: simplify 'st... |
499 500 |
memcpy(&cmd.hob, req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE - 2); memcpy(&cmd.tf, req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE); |
866e2ec9c ide: remove 'tf_i... |
501 |
|
60f85019c ide: replace IDE_... |
502 503 504 |
cmd.valid.out.tf = IDE_VALID_DEVICE; cmd.valid.in.tf = IDE_VALID_DEVICE | IDE_VALID_IN_TF; cmd.tf_flags = IDE_TFLAG_IO_16BIT; |
1da177e4c Linux-2.6.12-rc2 |
505 |
|
60f85019c ide: replace IDE_... |
506 507 508 509 |
if (drive->dev_flags & IDE_DFLAG_LBA48) { cmd.tf_flags |= IDE_TFLAG_LBA48; cmd.valid.in.hob = IDE_VALID_IN_HOB; } |
a3bbb9d88 ide: remove unnec... |
510 |
|
74095a91e ide: use do_rw_ta... |
511 |
if (req_task->out_flags.all) { |
22aa4b32a ide: remove ide_t... |
512 |
cmd.ftf_flags |= IDE_FTFLAG_FLAGGED; |
74095a91e ide: use do_rw_ta... |
513 514 |
if (req_task->out_flags.b.data) |
22aa4b32a ide: remove ide_t... |
515 |
cmd.ftf_flags |= IDE_FTFLAG_OUT_DATA; |
74095a91e ide: use do_rw_ta... |
516 517 |
if (req_task->out_flags.b.nsector_hob) |
60f85019c ide: replace IDE_... |
518 |
cmd.valid.out.hob |= IDE_VALID_NSECT; |
74095a91e ide: use do_rw_ta... |
519 |
if (req_task->out_flags.b.sector_hob) |
60f85019c ide: replace IDE_... |
520 |
cmd.valid.out.hob |= IDE_VALID_LBAL; |
74095a91e ide: use do_rw_ta... |
521 |
if (req_task->out_flags.b.lcyl_hob) |
60f85019c ide: replace IDE_... |
522 |
cmd.valid.out.hob |= IDE_VALID_LBAM; |
74095a91e ide: use do_rw_ta... |
523 |
if (req_task->out_flags.b.hcyl_hob) |
60f85019c ide: replace IDE_... |
524 |
cmd.valid.out.hob |= IDE_VALID_LBAH; |
74095a91e ide: use do_rw_ta... |
525 526 |
if (req_task->out_flags.b.error_feature) |
60f85019c ide: replace IDE_... |
527 |
cmd.valid.out.tf |= IDE_VALID_FEATURE; |
74095a91e ide: use do_rw_ta... |
528 |
if (req_task->out_flags.b.nsector) |
60f85019c ide: replace IDE_... |
529 |
cmd.valid.out.tf |= IDE_VALID_NSECT; |
74095a91e ide: use do_rw_ta... |
530 |
if (req_task->out_flags.b.sector) |
60f85019c ide: replace IDE_... |
531 |
cmd.valid.out.tf |= IDE_VALID_LBAL; |
74095a91e ide: use do_rw_ta... |
532 |
if (req_task->out_flags.b.lcyl) |
60f85019c ide: replace IDE_... |
533 |
cmd.valid.out.tf |= IDE_VALID_LBAM; |
74095a91e ide: use do_rw_ta... |
534 |
if (req_task->out_flags.b.hcyl) |
60f85019c ide: replace IDE_... |
535 |
cmd.valid.out.tf |= IDE_VALID_LBAH; |
a3bbb9d88 ide: remove unnec... |
536 |
} else { |
60f85019c ide: replace IDE_... |
537 |
cmd.valid.out.tf |= IDE_VALID_OUT_TF; |
22aa4b32a ide: remove ide_t... |
538 |
if (cmd.tf_flags & IDE_TFLAG_LBA48) |
60f85019c ide: replace IDE_... |
539 |
cmd.valid.out.hob |= IDE_VALID_OUT_HOB; |
74095a91e ide: use do_rw_ta... |
540 |
} |
866e2ec9c ide: remove 'tf_i... |
541 |
if (req_task->in_flags.b.data) |
22aa4b32a ide: remove ide_t... |
542 |
cmd.ftf_flags |= IDE_FTFLAG_IN_DATA; |
866e2ec9c ide: remove 'tf_i... |
543 |
|
04d09b0e6 ide: set IDE_TFLA... |
544 545 546 547 |
if (req_task->req_cmd == IDE_DRIVE_TASK_RAW_WRITE) { /* fixup data phase if needed */ if (req_task->data_phase == TASKFILE_IN_DMAQ || req_task->data_phase == TASKFILE_IN_DMA) |
0dfb991c6 ide: use ata_tf_p... |
548 |
cmd.tf_flags |= IDE_TFLAG_WRITE; |
04d09b0e6 ide: set IDE_TFLA... |
549 |
} |
0dfb991c6 ide: use ata_tf_p... |
550 551 552 |
cmd.protocol = ATA_PROT_DMA; switch (req_task->data_phase) { |
2d5abcede ide: ide-taskfile... |
553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 |
case TASKFILE_MULTI_OUT: if (!drive->mult_count) { /* (hs): give up if multcount is not set */ pr_err("%s: %s Multimode Write multcount is not set ", drive->name, __func__); err = -EPERM; goto abort; } cmd.tf_flags |= IDE_TFLAG_MULTI_PIO; /* fall through */ case TASKFILE_OUT: cmd.protocol = ATA_PROT_PIO; /* fall through */ case TASKFILE_OUT_DMAQ: case TASKFILE_OUT_DMA: cmd.tf_flags |= IDE_TFLAG_WRITE; nsect = taskout / SECTOR_SIZE; data_buf = outbuf; break; case TASKFILE_MULTI_IN: if (!drive->mult_count) { /* (hs): give up if multcount is not set */ pr_err("%s: %s Multimode Read multcount is not set ", drive->name, __func__); err = -EPERM; |
1da177e4c Linux-2.6.12-rc2 |
580 |
goto abort; |
2d5abcede ide: ide-taskfile... |
581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 |
} cmd.tf_flags |= IDE_TFLAG_MULTI_PIO; /* fall through */ case TASKFILE_IN: cmd.protocol = ATA_PROT_PIO; /* fall through */ case TASKFILE_IN_DMAQ: case TASKFILE_IN_DMA: nsect = taskin / SECTOR_SIZE; data_buf = inbuf; break; case TASKFILE_NO_DATA: cmd.protocol = ATA_PROT_NODATA; break; default: err = -EFAULT; goto abort; |
1da177e4c Linux-2.6.12-rc2 |
598 |
} |
ac026ff25 ide: remove 'comm... |
599 600 601 |
if (req_task->req_cmd == IDE_DRIVE_TASK_NO_DATA) nsect = 0; else if (!nsect) { |
745483f10 ide: simplify 'st... |
602 |
nsect = (cmd.hob.nsect << 8) | cmd.tf.nsect; |
ac026ff25 ide: remove 'comm... |
603 604 |
if (!nsect) { |
2d5abcede ide: ide-taskfile... |
605 606 |
pr_err("%s: in/out command without data ", |
ac026ff25 ide: remove 'comm... |
607 608 609 610 611 |
drive->name); err = -EFAULT; goto abort; } } |
22aa4b32a ide: remove ide_t... |
612 |
err = ide_raw_taskfile(drive, &cmd, data_buf, nsect); |
ac026ff25 ide: remove 'comm... |
613 |
|
745483f10 ide: simplify 'st... |
614 615 |
memcpy(req_task->hob_ports, &cmd.hob, HDIO_DRIVE_HOB_HDR_SIZE - 2); memcpy(req_task->io_ports, &cmd.tf, HDIO_DRIVE_TASK_HDR_SIZE); |
866e2ec9c ide: remove 'tf_i... |
616 |
|
22aa4b32a ide: remove ide_t... |
617 |
if ((cmd.ftf_flags & IDE_FTFLAG_SET_IN_FLAGS) && |
866e2ec9c ide: remove 'tf_i... |
618 619 |
req_task->in_flags.all == 0) { req_task->in_flags.all = IDE_TASKFILE_STD_IN_FLAGS; |
97100fc81 ide: add device f... |
620 |
if (drive->dev_flags & IDE_DFLAG_LBA48) |
866e2ec9c ide: remove 'tf_i... |
621 622 |
req_task->in_flags.all |= (IDE_HOB_STD_IN_FLAGS << 8); } |
1da177e4c Linux-2.6.12-rc2 |
623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 |
if (copy_to_user(buf, req_task, tasksize)) { err = -EFAULT; goto abort; } if (taskout) { int outtotal = tasksize; if (copy_to_user(buf + outtotal, outbuf, taskout)) { err = -EFAULT; goto abort; } } if (taskin) { int intotal = tasksize + taskout; if (copy_to_user(buf + intotal, inbuf, taskin)) { err = -EFAULT; goto abort; } } abort: kfree(req_task); |
6044ec888 [PATCH] kfree cle... |
644 645 |
kfree(outbuf); kfree(inbuf); |
1da177e4c Linux-2.6.12-rc2 |
646 |
|
1da177e4c Linux-2.6.12-rc2 |
647 648 |
return err; } |
26a5b0407 ide: add missing ... |
649 |
#endif |