]>
Commit | Line | Data |
---|---|---|
11938c92 BZ |
1 | |
2 | #include <linux/kernel.h> | |
5a0e3ad6 | 3 | #include <linux/gfp.h> |
11938c92 BZ |
4 | #include <linux/ide.h> |
5 | ||
6 | DEFINE_MUTEX(ide_setting_mtx); | |
7 | ||
8 | ide_devset_get(io_32bit, io_32bit); | |
9 | ||
10 | static int set_io_32bit(ide_drive_t *drive, int arg) | |
11 | { | |
12 | if (drive->dev_flags & IDE_DFLAG_NO_IO_32BIT) | |
13 | return -EPERM; | |
14 | ||
15 | if (arg < 0 || arg > 1 + (SUPPORT_VLB_SYNC << 1)) | |
16 | return -EINVAL; | |
17 | ||
18 | drive->io_32bit = arg; | |
19 | ||
20 | return 0; | |
21 | } | |
22 | ||
23 | ide_devset_get_flag(ksettings, IDE_DFLAG_KEEP_SETTINGS); | |
24 | ||
25 | static int set_ksettings(ide_drive_t *drive, int arg) | |
26 | { | |
27 | if (arg < 0 || arg > 1) | |
28 | return -EINVAL; | |
29 | ||
30 | if (arg) | |
31 | drive->dev_flags |= IDE_DFLAG_KEEP_SETTINGS; | |
32 | else | |
33 | drive->dev_flags &= ~IDE_DFLAG_KEEP_SETTINGS; | |
34 | ||
35 | return 0; | |
36 | } | |
37 | ||
38 | ide_devset_get_flag(using_dma, IDE_DFLAG_USING_DMA); | |
39 | ||
40 | static int set_using_dma(ide_drive_t *drive, int arg) | |
41 | { | |
42 | #ifdef CONFIG_BLK_DEV_IDEDMA | |
43 | int err = -EPERM; | |
44 | ||
45 | if (arg < 0 || arg > 1) | |
46 | return -EINVAL; | |
47 | ||
48 | if (ata_id_has_dma(drive->id) == 0) | |
49 | goto out; | |
50 | ||
51 | if (drive->hwif->dma_ops == NULL) | |
52 | goto out; | |
53 | ||
54 | err = 0; | |
55 | ||
56 | if (arg) { | |
57 | if (ide_set_dma(drive)) | |
58 | err = -EIO; | |
59 | } else | |
60 | ide_dma_off(drive); | |
61 | ||
62 | out: | |
63 | return err; | |
64 | #else | |
65 | if (arg < 0 || arg > 1) | |
66 | return -EINVAL; | |
67 | ||
68 | return -EPERM; | |
69 | #endif | |
70 | } | |
71 | ||
72 | /* | |
73 | * handle HDIO_SET_PIO_MODE ioctl abusers here, eventually it will go away | |
74 | */ | |
75 | static int set_pio_mode_abuse(ide_hwif_t *hwif, u8 req_pio) | |
76 | { | |
77 | switch (req_pio) { | |
78 | case 202: | |
79 | case 201: | |
80 | case 200: | |
81 | case 102: | |
82 | case 101: | |
83 | case 100: | |
84 | return (hwif->host_flags & IDE_HFLAG_ABUSE_DMA_MODES) ? 1 : 0; | |
85 | case 9: | |
86 | case 8: | |
87 | return (hwif->host_flags & IDE_HFLAG_ABUSE_PREFETCH) ? 1 : 0; | |
88 | case 7: | |
89 | case 6: | |
90 | return (hwif->host_flags & IDE_HFLAG_ABUSE_FAST_DEVSEL) ? 1 : 0; | |
91 | default: | |
92 | return 0; | |
93 | } | |
94 | } | |
95 | ||
96 | static int set_pio_mode(ide_drive_t *drive, int arg) | |
97 | { | |
98 | ide_hwif_t *hwif = drive->hwif; | |
99 | const struct ide_port_ops *port_ops = hwif->port_ops; | |
100 | ||
101 | if (arg < 0 || arg > 255) | |
102 | return -EINVAL; | |
103 | ||
104 | if (port_ops == NULL || port_ops->set_pio_mode == NULL || | |
105 | (hwif->host_flags & IDE_HFLAG_NO_SET_MODE)) | |
106 | return -ENOSYS; | |
107 | ||
108 | if (set_pio_mode_abuse(drive->hwif, arg)) { | |
d2d4e780 BZ |
109 | drive->pio_mode = arg + XFER_PIO_0; |
110 | ||
11938c92 BZ |
111 | if (arg == 8 || arg == 9) { |
112 | unsigned long flags; | |
113 | ||
114 | /* take lock for IDE_DFLAG_[NO_]UNMASK/[NO_]IO_32BIT */ | |
115 | spin_lock_irqsave(&hwif->lock, flags); | |
e085b3ca | 116 | port_ops->set_pio_mode(hwif, drive); |
11938c92 BZ |
117 | spin_unlock_irqrestore(&hwif->lock, flags); |
118 | } else | |
e085b3ca | 119 | port_ops->set_pio_mode(hwif, drive); |
11938c92 BZ |
120 | } else { |
121 | int keep_dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA); | |
122 | ||
123 | ide_set_pio(drive, arg); | |
124 | ||
125 | if (hwif->host_flags & IDE_HFLAG_SET_PIO_MODE_KEEP_DMA) { | |
126 | if (keep_dma) | |
127 | ide_dma_on(drive); | |
128 | } | |
129 | } | |
130 | ||
131 | return 0; | |
132 | } | |
133 | ||
134 | ide_devset_get_flag(unmaskirq, IDE_DFLAG_UNMASK); | |
135 | ||
136 | static int set_unmaskirq(ide_drive_t *drive, int arg) | |
137 | { | |
138 | if (drive->dev_flags & IDE_DFLAG_NO_UNMASK) | |
139 | return -EPERM; | |
140 | ||
141 | if (arg < 0 || arg > 1) | |
142 | return -EINVAL; | |
143 | ||
144 | if (arg) | |
145 | drive->dev_flags |= IDE_DFLAG_UNMASK; | |
146 | else | |
147 | drive->dev_flags &= ~IDE_DFLAG_UNMASK; | |
148 | ||
149 | return 0; | |
150 | } | |
151 | ||
152 | ide_ext_devset_rw_sync(io_32bit, io_32bit); | |
153 | ide_ext_devset_rw_sync(keepsettings, ksettings); | |
154 | ide_ext_devset_rw_sync(unmaskirq, unmaskirq); | |
155 | ide_ext_devset_rw_sync(using_dma, using_dma); | |
156 | __IDE_DEVSET(pio_mode, DS_SYNC, NULL, set_pio_mode); | |
157 | ||
158 | int ide_devset_execute(ide_drive_t *drive, const struct ide_devset *setting, | |
159 | int arg) | |
160 | { | |
161 | struct request_queue *q = drive->queue; | |
162 | struct request *rq; | |
163 | int ret = 0; | |
164 | ||
165 | if (!(setting->flags & DS_SYNC)) | |
166 | return setting->set(drive, arg); | |
167 | ||
aebf526b | 168 | rq = blk_get_request(q, REQ_OP_DRV_IN, __GFP_RECLAIM); |
2f5a8e80 | 169 | ide_req(rq)->type = ATA_PRIV_MISC; |
82ed4db4 CH |
170 | scsi_req(rq)->cmd_len = 5; |
171 | scsi_req(rq)->cmd[0] = REQ_DEVSET_EXEC; | |
172 | *(int *)&scsi_req(rq)->cmd[1] = arg; | |
11938c92 BZ |
173 | rq->special = setting->set; |
174 | ||
b7819b92 | 175 | blk_execute_rq(q, NULL, rq, 0); |
17d5363b | 176 | ret = scsi_req(rq)->result; |
11938c92 BZ |
177 | blk_put_request(rq); |
178 | ||
179 | return ret; | |
180 | } | |
181 | ||
182 | ide_startstop_t ide_do_devset(ide_drive_t *drive, struct request *rq) | |
183 | { | |
184 | int err, (*setfunc)(ide_drive_t *, int) = rq->special; | |
185 | ||
82ed4db4 | 186 | err = setfunc(drive, *(int *)&scsi_req(rq)->cmd[1]); |
11938c92 | 187 | if (err) |
17d5363b | 188 | scsi_req(rq)->result = err; |
1608fd1c | 189 | ide_complete_rq(drive, 0, blk_rq_bytes(rq)); |
11938c92 BZ |
190 | return ide_stopped; |
191 | } |