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