diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-10-11 16:22:33 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-10-11 16:22:33 -0400 |
commit | 5c3c4d9b5810c9aabd8c05219c62ca088aa83eb0 (patch) | |
tree | f1122247e0b6d6269588702738df9c46061e280d /drivers/ide/ide-atapi.c | |
parent | ead9d23d803ea3a73766c3cb27bf7563ac8d7266 (diff) | |
parent | 92f1f8fd8040e7b50a67a850a935509bb01201bb (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/bart/ide-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/bart/ide-2.6: (71 commits)
ide: Remove ide_spin_wait_hwgroup() and use special requests instead
ide: move IDE{FLOPPY,TAPE}_WAIT_CMD defines to <linux/ide.h>
ide: add ide_do_test_unit_ready() helper
ide: add ide_do_start_stop() helper
ide: add ide_set_media_lock() helper
ide-floppy: move floppy ioctls handling to ide-floppy_ioctl.c
ide-floppy: ->{srfp,wp} -> IDE_AFLAG_{SRFP,WP}
ide: add ide_queue_pc_tail() helper
ide: add ide_queue_pc_head() helper
ide: add ide_init_pc() helper
ide-tape: add ide_tape_set_media_lock() helper
ide-floppy: add ide_floppy_set_media_lock() helper
ide: add ide_io_buffers() helper
ide-scsi: cleanup ide_scsi_io_buffers()
ide-floppy: remove MODE_SENSE_* defines
ide-{floppy,tape}: remove packet command stack
ide-{floppy,tape}: remove request stack
ide-generic: handle probing of legacy io-ports v5
ide-floppy: use scatterlists for pio transfers
ide-tape: remove idetape_init_rq()
...
Diffstat (limited to 'drivers/ide/ide-atapi.c')
-rw-r--r-- | drivers/ide/ide-atapi.c | 236 |
1 files changed, 216 insertions, 20 deletions
diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c index adf04f99cdeb..608c5bade929 100644 --- a/drivers/ide/ide-atapi.c +++ b/drivers/ide/ide-atapi.c | |||
@@ -14,12 +14,201 @@ | |||
14 | #define debug_log(fmt, args...) do {} while (0) | 14 | #define debug_log(fmt, args...) do {} while (0) |
15 | #endif | 15 | #endif |
16 | 16 | ||
17 | /* | ||
18 | * Check whether we can support a device, | ||
19 | * based on the ATAPI IDENTIFY command results. | ||
20 | */ | ||
21 | int ide_check_atapi_device(ide_drive_t *drive, const char *s) | ||
22 | { | ||
23 | u16 *id = drive->id; | ||
24 | u8 gcw[2], protocol, device_type, removable, drq_type, packet_size; | ||
25 | |||
26 | *((u16 *)&gcw) = id[ATA_ID_CONFIG]; | ||
27 | |||
28 | protocol = (gcw[1] & 0xC0) >> 6; | ||
29 | device_type = gcw[1] & 0x1F; | ||
30 | removable = (gcw[0] & 0x80) >> 7; | ||
31 | drq_type = (gcw[0] & 0x60) >> 5; | ||
32 | packet_size = gcw[0] & 0x03; | ||
33 | |||
34 | #ifdef CONFIG_PPC | ||
35 | /* kludge for Apple PowerBook internal zip */ | ||
36 | if (drive->media == ide_floppy && device_type == 5 && | ||
37 | !strstr((char *)&id[ATA_ID_PROD], "CD-ROM") && | ||
38 | strstr((char *)&id[ATA_ID_PROD], "ZIP")) | ||
39 | device_type = 0; | ||
40 | #endif | ||
41 | |||
42 | if (protocol != 2) | ||
43 | printk(KERN_ERR "%s: %s: protocol (0x%02x) is not ATAPI\n", | ||
44 | s, drive->name, protocol); | ||
45 | else if ((drive->media == ide_floppy && device_type != 0) || | ||
46 | (drive->media == ide_tape && device_type != 1)) | ||
47 | printk(KERN_ERR "%s: %s: invalid device type (0x%02x)\n", | ||
48 | s, drive->name, device_type); | ||
49 | else if (removable == 0) | ||
50 | printk(KERN_ERR "%s: %s: the removable flag is not set\n", | ||
51 | s, drive->name); | ||
52 | else if (drive->media == ide_floppy && drq_type == 3) | ||
53 | printk(KERN_ERR "%s: %s: sorry, DRQ type (0x%02x) not " | ||
54 | "supported\n", s, drive->name, drq_type); | ||
55 | else if (packet_size != 0) | ||
56 | printk(KERN_ERR "%s: %s: packet size (0x%02x) is not 12 " | ||
57 | "bytes\n", s, drive->name, packet_size); | ||
58 | else | ||
59 | return 1; | ||
60 | return 0; | ||
61 | } | ||
62 | EXPORT_SYMBOL_GPL(ide_check_atapi_device); | ||
63 | |||
64 | /* PIO data transfer routine using the scatter gather table. */ | ||
65 | int ide_io_buffers(ide_drive_t *drive, struct ide_atapi_pc *pc, | ||
66 | unsigned int bcount, int write) | ||
67 | { | ||
68 | ide_hwif_t *hwif = drive->hwif; | ||
69 | const struct ide_tp_ops *tp_ops = hwif->tp_ops; | ||
70 | xfer_func_t *xf = write ? tp_ops->output_data : tp_ops->input_data; | ||
71 | struct scatterlist *sg = pc->sg; | ||
72 | char *buf; | ||
73 | int count, done = 0; | ||
74 | |||
75 | while (bcount) { | ||
76 | count = min(sg->length - pc->b_count, bcount); | ||
77 | |||
78 | if (PageHighMem(sg_page(sg))) { | ||
79 | unsigned long flags; | ||
80 | |||
81 | local_irq_save(flags); | ||
82 | buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset; | ||
83 | xf(drive, NULL, buf + pc->b_count, count); | ||
84 | kunmap_atomic(buf - sg->offset, KM_IRQ0); | ||
85 | local_irq_restore(flags); | ||
86 | } else { | ||
87 | buf = sg_virt(sg); | ||
88 | xf(drive, NULL, buf + pc->b_count, count); | ||
89 | } | ||
90 | |||
91 | bcount -= count; | ||
92 | pc->b_count += count; | ||
93 | done += count; | ||
94 | |||
95 | if (pc->b_count == sg->length) { | ||
96 | if (!--pc->sg_cnt) | ||
97 | break; | ||
98 | pc->sg = sg = sg_next(sg); | ||
99 | pc->b_count = 0; | ||
100 | } | ||
101 | } | ||
102 | |||
103 | if (bcount) { | ||
104 | printk(KERN_ERR "%s: %d leftover bytes, %s\n", drive->name, | ||
105 | bcount, write ? "padding with zeros" | ||
106 | : "discarding data"); | ||
107 | ide_pad_transfer(drive, write, bcount); | ||
108 | } | ||
109 | |||
110 | return done; | ||
111 | } | ||
112 | EXPORT_SYMBOL_GPL(ide_io_buffers); | ||
113 | |||
114 | void ide_init_pc(struct ide_atapi_pc *pc) | ||
115 | { | ||
116 | memset(pc, 0, sizeof(*pc)); | ||
117 | pc->buf = pc->pc_buf; | ||
118 | pc->buf_size = IDE_PC_BUFFER_SIZE; | ||
119 | } | ||
120 | EXPORT_SYMBOL_GPL(ide_init_pc); | ||
121 | |||
122 | /* | ||
123 | * Generate a new packet command request in front of the request queue, before | ||
124 | * the current request, so that it will be processed immediately, on the next | ||
125 | * pass through the driver. | ||
126 | */ | ||
127 | void ide_queue_pc_head(ide_drive_t *drive, struct gendisk *disk, | ||
128 | struct ide_atapi_pc *pc, struct request *rq) | ||
129 | { | ||
130 | blk_rq_init(NULL, rq); | ||
131 | rq->cmd_type = REQ_TYPE_SPECIAL; | ||
132 | rq->cmd_flags |= REQ_PREEMPT; | ||
133 | rq->buffer = (char *)pc; | ||
134 | rq->rq_disk = disk; | ||
135 | memcpy(rq->cmd, pc->c, 12); | ||
136 | if (drive->media == ide_tape) | ||
137 | rq->cmd[13] = REQ_IDETAPE_PC1; | ||
138 | ide_do_drive_cmd(drive, rq); | ||
139 | } | ||
140 | EXPORT_SYMBOL_GPL(ide_queue_pc_head); | ||
141 | |||
142 | /* | ||
143 | * Add a special packet command request to the tail of the request queue, | ||
144 | * and wait for it to be serviced. | ||
145 | */ | ||
146 | int ide_queue_pc_tail(ide_drive_t *drive, struct gendisk *disk, | ||
147 | struct ide_atapi_pc *pc) | ||
148 | { | ||
149 | struct request *rq; | ||
150 | int error; | ||
151 | |||
152 | rq = blk_get_request(drive->queue, READ, __GFP_WAIT); | ||
153 | rq->cmd_type = REQ_TYPE_SPECIAL; | ||
154 | rq->buffer = (char *)pc; | ||
155 | memcpy(rq->cmd, pc->c, 12); | ||
156 | if (drive->media == ide_tape) | ||
157 | rq->cmd[13] = REQ_IDETAPE_PC1; | ||
158 | error = blk_execute_rq(drive->queue, disk, rq, 0); | ||
159 | blk_put_request(rq); | ||
160 | |||
161 | return error; | ||
162 | } | ||
163 | EXPORT_SYMBOL_GPL(ide_queue_pc_tail); | ||
164 | |||
165 | int ide_do_test_unit_ready(ide_drive_t *drive, struct gendisk *disk) | ||
166 | { | ||
167 | struct ide_atapi_pc pc; | ||
168 | |||
169 | ide_init_pc(&pc); | ||
170 | pc.c[0] = TEST_UNIT_READY; | ||
171 | |||
172 | return ide_queue_pc_tail(drive, disk, &pc); | ||
173 | } | ||
174 | EXPORT_SYMBOL_GPL(ide_do_test_unit_ready); | ||
175 | |||
176 | int ide_do_start_stop(ide_drive_t *drive, struct gendisk *disk, int start) | ||
177 | { | ||
178 | struct ide_atapi_pc pc; | ||
179 | |||
180 | ide_init_pc(&pc); | ||
181 | pc.c[0] = START_STOP; | ||
182 | pc.c[4] = start; | ||
183 | |||
184 | if (drive->media == ide_tape) | ||
185 | pc.flags |= PC_FLAG_WAIT_FOR_DSC; | ||
186 | |||
187 | return ide_queue_pc_tail(drive, disk, &pc); | ||
188 | } | ||
189 | EXPORT_SYMBOL_GPL(ide_do_start_stop); | ||
190 | |||
191 | int ide_set_media_lock(ide_drive_t *drive, struct gendisk *disk, int on) | ||
192 | { | ||
193 | struct ide_atapi_pc pc; | ||
194 | |||
195 | if (drive->atapi_flags & IDE_AFLAG_NO_DOORLOCK) | ||
196 | return 0; | ||
197 | |||
198 | ide_init_pc(&pc); | ||
199 | pc.c[0] = ALLOW_MEDIUM_REMOVAL; | ||
200 | pc.c[4] = on; | ||
201 | |||
202 | return ide_queue_pc_tail(drive, disk, &pc); | ||
203 | } | ||
204 | EXPORT_SYMBOL_GPL(ide_set_media_lock); | ||
205 | |||
17 | /* TODO: unify the code thus making some arguments go away */ | 206 | /* TODO: unify the code thus making some arguments go away */ |
18 | ide_startstop_t ide_pc_intr(ide_drive_t *drive, struct ide_atapi_pc *pc, | 207 | ide_startstop_t ide_pc_intr(ide_drive_t *drive, struct ide_atapi_pc *pc, |
19 | ide_handler_t *handler, unsigned int timeout, ide_expiry_t *expiry, | 208 | ide_handler_t *handler, unsigned int timeout, ide_expiry_t *expiry, |
20 | void (*update_buffers)(ide_drive_t *, struct ide_atapi_pc *), | 209 | void (*update_buffers)(ide_drive_t *, struct ide_atapi_pc *), |
21 | void (*retry_pc)(ide_drive_t *), void (*dsc_handle)(ide_drive_t *), | 210 | void (*retry_pc)(ide_drive_t *), void (*dsc_handle)(ide_drive_t *), |
22 | void (*io_buffers)(ide_drive_t *, struct ide_atapi_pc *, unsigned, int)) | 211 | int (*io_buffers)(ide_drive_t *, struct ide_atapi_pc *, unsigned, int)) |
23 | { | 212 | { |
24 | ide_hwif_t *hwif = drive->hwif; | 213 | ide_hwif_t *hwif = drive->hwif; |
25 | struct request *rq = hwif->hwgroup->rq; | 214 | struct request *rq = hwif->hwgroup->rq; |
@@ -41,7 +230,7 @@ ide_startstop_t ide_pc_intr(ide_drive_t *drive, struct ide_atapi_pc *pc, | |||
41 | 230 | ||
42 | if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) { | 231 | if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) { |
43 | if (hwif->dma_ops->dma_end(drive) || | 232 | if (hwif->dma_ops->dma_end(drive) || |
44 | (drive->media == ide_tape && !scsi && (stat & ERR_STAT))) { | 233 | (drive->media == ide_tape && !scsi && (stat & ATA_ERR))) { |
45 | if (drive->media == ide_floppy && !scsi) | 234 | if (drive->media == ide_floppy && !scsi) |
46 | printk(KERN_ERR "%s: DMA %s error\n", | 235 | printk(KERN_ERR "%s: DMA %s error\n", |
47 | drive->name, rq_data_dir(pc->rq) | 236 | drive->name, rq_data_dir(pc->rq) |
@@ -56,7 +245,7 @@ ide_startstop_t ide_pc_intr(ide_drive_t *drive, struct ide_atapi_pc *pc, | |||
56 | } | 245 | } |
57 | 246 | ||
58 | /* No more interrupts */ | 247 | /* No more interrupts */ |
59 | if ((stat & DRQ_STAT) == 0) { | 248 | if ((stat & ATA_DRQ) == 0) { |
60 | debug_log("Packet command completed, %d bytes transferred\n", | 249 | debug_log("Packet command completed, %d bytes transferred\n", |
61 | pc->xferred); | 250 | pc->xferred); |
62 | 251 | ||
@@ -65,10 +254,10 @@ ide_startstop_t ide_pc_intr(ide_drive_t *drive, struct ide_atapi_pc *pc, | |||
65 | local_irq_enable_in_hardirq(); | 254 | local_irq_enable_in_hardirq(); |
66 | 255 | ||
67 | if (drive->media == ide_tape && !scsi && | 256 | if (drive->media == ide_tape && !scsi && |
68 | (stat & ERR_STAT) && rq->cmd[0] == REQUEST_SENSE) | 257 | (stat & ATA_ERR) && rq->cmd[0] == REQUEST_SENSE) |
69 | stat &= ~ERR_STAT; | 258 | stat &= ~ATA_ERR; |
70 | 259 | ||
71 | if ((stat & ERR_STAT) || (pc->flags & PC_FLAG_DMA_ERROR)) { | 260 | if ((stat & ATA_ERR) || (pc->flags & PC_FLAG_DMA_ERROR)) { |
72 | /* Error detected */ | 261 | /* Error detected */ |
73 | debug_log("%s: I/O error\n", drive->name); | 262 | debug_log("%s: I/O error\n", drive->name); |
74 | 263 | ||
@@ -95,7 +284,7 @@ ide_startstop_t ide_pc_intr(ide_drive_t *drive, struct ide_atapi_pc *pc, | |||
95 | cmd_finished: | 284 | cmd_finished: |
96 | pc->error = 0; | 285 | pc->error = 0; |
97 | if ((pc->flags & PC_FLAG_WAIT_FOR_DSC) && | 286 | if ((pc->flags & PC_FLAG_WAIT_FOR_DSC) && |
98 | (stat & SEEK_STAT) == 0) { | 287 | (stat & ATA_DSC) == 0) { |
99 | dsc_handle(drive); | 288 | dsc_handle(drive); |
100 | return ide_stopped; | 289 | return ide_stopped; |
101 | } | 290 | } |
@@ -117,17 +306,18 @@ cmd_finished: | |||
117 | /* Get the number of bytes to transfer on this interrupt. */ | 306 | /* Get the number of bytes to transfer on this interrupt. */ |
118 | ide_read_bcount_and_ireason(drive, &bcount, &ireason); | 307 | ide_read_bcount_and_ireason(drive, &bcount, &ireason); |
119 | 308 | ||
120 | if (ireason & CD) { | 309 | if (ireason & ATAPI_COD) { |
121 | printk(KERN_ERR "%s: CoD != 0 in %s\n", drive->name, __func__); | 310 | printk(KERN_ERR "%s: CoD != 0 in %s\n", drive->name, __func__); |
122 | return ide_do_reset(drive); | 311 | return ide_do_reset(drive); |
123 | } | 312 | } |
124 | 313 | ||
125 | if (((ireason & IO) == IO) == !!(pc->flags & PC_FLAG_WRITING)) { | 314 | if (((ireason & ATAPI_IO) == ATAPI_IO) == |
315 | !!(pc->flags & PC_FLAG_WRITING)) { | ||
126 | /* Hopefully, we will never get here */ | 316 | /* Hopefully, we will never get here */ |
127 | printk(KERN_ERR "%s: We wanted to %s, but the device wants us " | 317 | printk(KERN_ERR "%s: We wanted to %s, but the device wants us " |
128 | "to %s!\n", drive->name, | 318 | "to %s!\n", drive->name, |
129 | (ireason & IO) ? "Write" : "Read", | 319 | (ireason & ATAPI_IO) ? "Write" : "Read", |
130 | (ireason & IO) ? "Read" : "Write"); | 320 | (ireason & ATAPI_IO) ? "Read" : "Write"); |
131 | return ide_do_reset(drive); | 321 | return ide_do_reset(drive); |
132 | } | 322 | } |
133 | 323 | ||
@@ -171,9 +361,14 @@ cmd_finished: | |||
171 | 361 | ||
172 | if ((drive->media == ide_floppy && !scsi && !pc->buf) || | 362 | if ((drive->media == ide_floppy && !scsi && !pc->buf) || |
173 | (drive->media == ide_tape && !scsi && pc->bh) || | 363 | (drive->media == ide_tape && !scsi && pc->bh) || |
174 | (scsi && pc->sg)) | 364 | (scsi && pc->sg)) { |
175 | io_buffers(drive, pc, bcount, !!(pc->flags & PC_FLAG_WRITING)); | 365 | int done = io_buffers(drive, pc, bcount, |
176 | else | 366 | !!(pc->flags & PC_FLAG_WRITING)); |
367 | |||
368 | /* FIXME: don't do partial completions */ | ||
369 | if (drive->media == ide_floppy && !scsi) | ||
370 | ide_end_request(drive, 1, done >> 9); | ||
371 | } else | ||
177 | xferfunc(drive, NULL, pc->cur_pos, bcount); | 372 | xferfunc(drive, NULL, pc->cur_pos, bcount); |
178 | 373 | ||
179 | /* Update the current position */ | 374 | /* Update the current position */ |
@@ -205,7 +400,8 @@ static u8 ide_wait_ireason(ide_drive_t *drive, u8 ireason) | |||
205 | { | 400 | { |
206 | int retries = 100; | 401 | int retries = 100; |
207 | 402 | ||
208 | while (retries-- && ((ireason & CD) == 0 || (ireason & IO))) { | 403 | while (retries-- && ((ireason & ATAPI_COD) == 0 || |
404 | (ireason & ATAPI_IO))) { | ||
209 | printk(KERN_ERR "%s: (IO,CoD != (0,1) while issuing " | 405 | printk(KERN_ERR "%s: (IO,CoD != (0,1) while issuing " |
210 | "a packet command, retrying\n", drive->name); | 406 | "a packet command, retrying\n", drive->name); |
211 | udelay(100); | 407 | udelay(100); |
@@ -214,8 +410,8 @@ static u8 ide_wait_ireason(ide_drive_t *drive, u8 ireason) | |||
214 | printk(KERN_ERR "%s: (IO,CoD != (0,1) while issuing " | 410 | printk(KERN_ERR "%s: (IO,CoD != (0,1) while issuing " |
215 | "a packet command, ignoring\n", | 411 | "a packet command, ignoring\n", |
216 | drive->name); | 412 | drive->name); |
217 | ireason |= CD; | 413 | ireason |= ATAPI_COD; |
218 | ireason &= ~IO; | 414 | ireason &= ~ATAPI_IO; |
219 | } | 415 | } |
220 | } | 416 | } |
221 | 417 | ||
@@ -231,7 +427,7 @@ ide_startstop_t ide_transfer_pc(ide_drive_t *drive, struct ide_atapi_pc *pc, | |||
231 | ide_startstop_t startstop; | 427 | ide_startstop_t startstop; |
232 | u8 ireason; | 428 | u8 ireason; |
233 | 429 | ||
234 | if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) { | 430 | if (ide_wait_stat(&startstop, drive, ATA_DRQ, ATA_BUSY, WAIT_READY)) { |
235 | printk(KERN_ERR "%s: Strange, packet command initiated yet " | 431 | printk(KERN_ERR "%s: Strange, packet command initiated yet " |
236 | "DRQ isn't asserted\n", drive->name); | 432 | "DRQ isn't asserted\n", drive->name); |
237 | return startstop; | 433 | return startstop; |
@@ -241,7 +437,7 @@ ide_startstop_t ide_transfer_pc(ide_drive_t *drive, struct ide_atapi_pc *pc, | |||
241 | if (drive->media == ide_tape && !drive->scsi) | 437 | if (drive->media == ide_tape && !drive->scsi) |
242 | ireason = ide_wait_ireason(drive, ireason); | 438 | ireason = ide_wait_ireason(drive, ireason); |
243 | 439 | ||
244 | if ((ireason & CD) == 0 || (ireason & IO)) { | 440 | if ((ireason & ATAPI_COD) == 0 || (ireason & ATAPI_IO)) { |
245 | printk(KERN_ERR "%s: (IO,CoD) != (0,1) while issuing " | 441 | printk(KERN_ERR "%s: (IO,CoD) != (0,1) while issuing " |
246 | "a packet command\n", drive->name); | 442 | "a packet command\n", drive->name); |
247 | return ide_do_reset(drive); | 443 | return ide_do_reset(drive); |
@@ -303,7 +499,7 @@ ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_atapi_pc *pc, | |||
303 | 499 | ||
304 | /* Issue the packet command */ | 500 | /* Issue the packet command */ |
305 | if (drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT) { | 501 | if (drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT) { |
306 | ide_execute_command(drive, WIN_PACKETCMD, handler, | 502 | ide_execute_command(drive, ATA_CMD_PACKET, handler, |
307 | timeout, NULL); | 503 | timeout, NULL); |
308 | return ide_started; | 504 | return ide_started; |
309 | } else { | 505 | } else { |