xref: /openbmc/qemu/hw/block/swim.c (revision 7d5dc0a3)
1 /*
2  * QEMU Macintosh floppy disk controller emulator (SWIM)
3  *
4  * Copyright (c) 2014-2018 Laurent Vivier <laurent@vivier.eu>
5  *
6  * This work is licensed under the terms of the GNU GPL, version 2.  See
7  * the COPYING file in the top-level directory.
8  *
9  * Only the basic support: it allows to switch from IWM (Integrated WOZ
10  * Machine) mode to the SWIM mode and makes the linux driver happy.
11  */
12 
13 #include "qemu/osdep.h"
14 #include "qemu/main-loop.h"
15 #include "qapi/error.h"
16 #include "sysemu/block-backend.h"
17 #include "hw/sysbus.h"
18 #include "migration/vmstate.h"
19 #include "hw/block/block.h"
20 #include "hw/block/swim.h"
21 #include "hw/qdev-properties.h"
22 #include "trace.h"
23 
24 
25 /* IWM latch bits */
26 
27 #define IWMLB_PHASE0            0
28 #define IWMLB_PHASE1            1
29 #define IWMLB_PHASE2            2
30 #define IWMLB_PHASE3            3
31 #define IWMLB_MOTORON           4
32 #define IWMLB_DRIVESEL          5
33 #define IWMLB_L6                6
34 #define IWMLB_L7                7
35 
36 /* IWM registers */
37 
38 #define IWM_READALLONES         0
39 #define IWM_READDATA            1
40 #define IWM_READSTATUS0         2
41 #define IWM_READSTATUS1         3
42 #define IWM_READWHANDSHAKE0     4
43 #define IWM_READWHANDSHAKE1     5
44 #define IWM_WRITESETMODE        6
45 #define IWM_WRITEDATA           7
46 
47 /* SWIM registers */
48 
49 #define SWIM_WRITE_DATA         0
50 #define SWIM_WRITE_MARK         1
51 #define SWIM_WRITE_CRC          2
52 #define SWIM_WRITE_PARAMETER    3
53 #define SWIM_WRITE_PHASE        4
54 #define SWIM_WRITE_SETUP        5
55 #define SWIM_WRITE_MODE0        6
56 #define SWIM_WRITE_MODE1        7
57 
58 #define SWIM_READ_DATA          8
59 #define SWIM_READ_MARK          9
60 #define SWIM_READ_ERROR         10
61 #define SWIM_READ_PARAMETER     11
62 #define SWIM_READ_PHASE         12
63 #define SWIM_READ_SETUP         13
64 #define SWIM_READ_STATUS        14
65 #define SWIM_READ_HANDSHAKE     15
66 
67 #define REG_SHIFT               9
68 
69 #define SWIM_MODE_STATUS_BIT    6
70 #define SWIM_MODE_IWM           0
71 #define SWIM_MODE_ISM           1
72 
73 /* bits in phase register */
74 
75 #define SWIM_SEEK_NEGATIVE   0x074
76 #define SWIM_STEP            0x071
77 #define SWIM_MOTOR_ON        0x072
78 #define SWIM_MOTOR_OFF       0x076
79 #define SWIM_INDEX           0x073
80 #define SWIM_EJECT           0x077
81 #define SWIM_SETMFM          0x171
82 #define SWIM_SETGCR          0x175
83 #define SWIM_RELAX           0x033
84 #define SWIM_LSTRB           0x008
85 #define SWIM_CA_MASK         0x077
86 
87 /* Select values for swim_select and swim_readbit */
88 
89 #define SWIM_READ_DATA_0     0x074
90 #define SWIM_TWOMEG_DRIVE    0x075
91 #define SWIM_SINGLE_SIDED    0x076
92 #define SWIM_DRIVE_PRESENT   0x077
93 #define SWIM_DISK_IN         0x170
94 #define SWIM_WRITE_PROT      0x171
95 #define SWIM_TRACK_ZERO      0x172
96 #define SWIM_TACHO           0x173
97 #define SWIM_READ_DATA_1     0x174
98 #define SWIM_MFM_MODE        0x175
99 #define SWIM_SEEK_COMPLETE   0x176
100 #define SWIM_ONEMEG_MEDIA    0x177
101 
102 /* Bits in handshake register */
103 
104 #define SWIM_MARK_BYTE       0x01
105 #define SWIM_CRC_ZERO        0x02
106 #define SWIM_RDDATA          0x04
107 #define SWIM_SENSE           0x08
108 #define SWIM_MOTEN           0x10
109 #define SWIM_ERROR           0x20
110 #define SWIM_DAT2BYTE        0x40
111 #define SWIM_DAT1BYTE        0x80
112 
113 /* bits in setup register */
114 
115 #define SWIM_S_INV_WDATA     0x01
116 #define SWIM_S_3_5_SELECT    0x02
117 #define SWIM_S_GCR           0x04
118 #define SWIM_S_FCLK_DIV2     0x08
119 #define SWIM_S_ERROR_CORR    0x10
120 #define SWIM_S_IBM_DRIVE     0x20
121 #define SWIM_S_GCR_WRITE     0x40
122 #define SWIM_S_TIMEOUT       0x80
123 
124 /* bits in mode register */
125 
126 #define SWIM_CLFIFO          0x01
127 #define SWIM_ENBL1           0x02
128 #define SWIM_ENBL2           0x04
129 #define SWIM_ACTION          0x08
130 #define SWIM_WRITE_MODE      0x10
131 #define SWIM_HEDSEL          0x20
132 #define SWIM_MOTON           0x80
133 
134 static const char *iwm_reg_names[] = {
135     "READALLONES", "READDATA", "READSTATUS0", "READSTATUS1",
136     "READWHANDSHAKE0", "READWHANDSHAKE1", "WRITESETMODE", "WRITEDATA"
137 };
138 
139 static const char *ism_reg_names[] = {
140     "WRITE_DATA", "WRITE_MARK", "WRITE_CRC", "WRITE_PARAMETER",
141     "WRITE_PHASE", "WRITE_SETUP", "WRITE_MODE0", "WRITE_MODE1",
142     "READ_DATA", "READ_MARK", "READ_ERROR", "READ_PARAMETER",
143     "READ_PHASE", "READ_SETUP", "READ_STATUS", "READ_HANDSHAKE"
144 };
145 
fd_recalibrate(FDrive * drive)146 static void fd_recalibrate(FDrive *drive)
147 {
148 }
149 
swim_change_cb(void * opaque,bool load,Error ** errp)150 static void swim_change_cb(void *opaque, bool load, Error **errp)
151 {
152     FDrive *drive = opaque;
153 
154     if (!load) {
155         blk_set_perm(drive->blk, 0, BLK_PERM_ALL, &error_abort);
156     } else {
157         if (!blkconf_apply_backend_options(drive->conf,
158                                            !blk_supports_write_perm(drive->blk),
159                                            false, errp)) {
160             return;
161         }
162     }
163 }
164 
165 static const BlockDevOps swim_block_ops = {
166     .change_media_cb = swim_change_cb,
167 };
168 
169 static Property swim_drive_properties[] = {
170     DEFINE_PROP_INT32("unit", SWIMDrive, unit, -1),
171     DEFINE_BLOCK_PROPERTIES(SWIMDrive, conf),
172     DEFINE_PROP_END_OF_LIST(),
173 };
174 
swim_drive_realize(DeviceState * qdev,Error ** errp)175 static void swim_drive_realize(DeviceState *qdev, Error **errp)
176 {
177     SWIMDrive *dev = SWIM_DRIVE(qdev);
178     SWIMBus *bus = SWIM_BUS(qdev->parent_bus);
179     FDrive *drive;
180     int ret;
181 
182     if (dev->unit == -1) {
183         for (dev->unit = 0; dev->unit < SWIM_MAX_FD; dev->unit++) {
184             drive = &bus->ctrl->drives[dev->unit];
185             if (!drive->blk) {
186                 break;
187             }
188         }
189     }
190 
191     if (dev->unit >= SWIM_MAX_FD) {
192         error_setg(errp, "Can't create floppy unit %d, bus supports "
193                    "only %d units", dev->unit, SWIM_MAX_FD);
194         return;
195     }
196 
197     drive = &bus->ctrl->drives[dev->unit];
198     if (drive->blk) {
199         error_setg(errp, "Floppy unit %d is in use", dev->unit);
200         return;
201     }
202 
203     if (!dev->conf.blk) {
204         /* Anonymous BlockBackend for an empty drive */
205         dev->conf.blk = blk_new(qemu_get_aio_context(), 0, BLK_PERM_ALL);
206         ret = blk_attach_dev(dev->conf.blk, qdev);
207         assert(ret == 0);
208     }
209 
210     if (!blkconf_blocksizes(&dev->conf, errp)) {
211         return;
212     }
213 
214     if (dev->conf.logical_block_size != 512 ||
215         dev->conf.physical_block_size != 512)
216     {
217         error_setg(errp, "Physical and logical block size must "
218                    "be 512 for floppy");
219         return;
220     }
221 
222     /*
223      * rerror/werror aren't supported by fdc and therefore not even registered
224      * with qdev. So set the defaults manually before they are used in
225      * blkconf_apply_backend_options().
226      */
227     dev->conf.rerror = BLOCKDEV_ON_ERROR_AUTO;
228     dev->conf.werror = BLOCKDEV_ON_ERROR_AUTO;
229 
230     if (!blkconf_apply_backend_options(&dev->conf,
231                                        !blk_supports_write_perm(dev->conf.blk),
232                                        false, errp)) {
233         return;
234     }
235 
236     /*
237      * 'enospc' is the default for -drive, 'report' is what blk_new() gives us
238      * for empty drives.
239      */
240     if (blk_get_on_error(dev->conf.blk, 0) != BLOCKDEV_ON_ERROR_ENOSPC &&
241         blk_get_on_error(dev->conf.blk, 0) != BLOCKDEV_ON_ERROR_REPORT) {
242         error_setg(errp, "fdc doesn't support drive option werror");
243         return;
244     }
245     if (blk_get_on_error(dev->conf.blk, 1) != BLOCKDEV_ON_ERROR_REPORT) {
246         error_setg(errp, "fdc doesn't support drive option rerror");
247         return;
248     }
249 
250     drive->conf = &dev->conf;
251     drive->blk = dev->conf.blk;
252     drive->swimctrl = bus->ctrl;
253 
254     blk_set_dev_ops(drive->blk, &swim_block_ops, drive);
255 }
256 
swim_drive_class_init(ObjectClass * klass,void * data)257 static void swim_drive_class_init(ObjectClass *klass, void *data)
258 {
259     DeviceClass *k = DEVICE_CLASS(klass);
260     k->realize = swim_drive_realize;
261     set_bit(DEVICE_CATEGORY_STORAGE, k->categories);
262     k->bus_type = TYPE_SWIM_BUS;
263     device_class_set_props(k, swim_drive_properties);
264     k->desc = "virtual SWIM drive";
265 }
266 
267 static const TypeInfo swim_drive_info = {
268     .name = TYPE_SWIM_DRIVE,
269     .parent = TYPE_DEVICE,
270     .instance_size = sizeof(SWIMDrive),
271     .class_init = swim_drive_class_init,
272 };
273 
274 static const TypeInfo swim_bus_info = {
275     .name = TYPE_SWIM_BUS,
276     .parent = TYPE_BUS,
277     .instance_size = sizeof(SWIMBus),
278 };
279 
iwmctrl_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)280 static void iwmctrl_write(void *opaque, hwaddr addr, uint64_t value,
281                           unsigned size)
282 {
283     SWIMCtrl *swimctrl = opaque;
284     uint8_t latch, reg, ism_bit;
285 
286     addr >>= REG_SHIFT;
287 
288     /* A3-A1 select a latch, A0 specifies the value */
289     latch = (addr >> 1) & 7;
290     if (addr & 1) {
291         swimctrl->iwm_latches |= (1 << latch);
292     } else {
293         swimctrl->iwm_latches &= ~(1 << latch);
294     }
295 
296     reg = (swimctrl->iwm_latches & 0xc0) >> 5 |
297           (swimctrl->iwm_latches & 0x10) >> 4;
298 
299     swimctrl->iwmregs[reg] = value;
300     trace_swim_iwmctrl_write(reg, iwm_reg_names[reg], size, value);
301 
302     switch (reg) {
303     case IWM_WRITESETMODE:
304         /* detect sequence to switch from IWM mode to SWIM mode */
305         ism_bit = (value & (1 << SWIM_MODE_STATUS_BIT));
306 
307         switch (swimctrl->iwm_switch) {
308         case 0:
309             if (ism_bit) {    /* 1 */
310                 swimctrl->iwm_switch++;
311             }
312             break;
313         case 1:
314             if (!ism_bit) {   /* 0 */
315                 swimctrl->iwm_switch++;
316             }
317             break;
318         case 2:
319             if (ism_bit) {    /* 1 */
320                 swimctrl->iwm_switch++;
321             }
322             break;
323         case 3:
324             if (ism_bit) {    /* 1 */
325                 swimctrl->iwm_switch++;
326 
327                 swimctrl->mode = SWIM_MODE_ISM;
328                 swimctrl->swim_mode |= (1 << SWIM_MODE_STATUS_BIT);
329                 swimctrl->iwm_switch = 0;
330                 trace_swim_switch_to_ism();
331 
332                 /* Switch to ISM registers */
333                 memory_region_del_subregion(&swimctrl->swim, &swimctrl->iwm);
334                 memory_region_add_subregion(&swimctrl->swim, 0x0,
335                                             &swimctrl->ism);
336             }
337             break;
338         }
339         break;
340     default:
341         break;
342     }
343 }
344 
iwmctrl_read(void * opaque,hwaddr addr,unsigned size)345 static uint64_t iwmctrl_read(void *opaque, hwaddr addr, unsigned size)
346 {
347     SWIMCtrl *swimctrl = opaque;
348     uint8_t latch, reg, value;
349 
350     addr >>= REG_SHIFT;
351 
352     /* A3-A1 select a latch, A0 specifies the value */
353     latch = (addr >> 1) & 7;
354     if (addr & 1) {
355         swimctrl->iwm_latches |= (1 << latch);
356     } else {
357         swimctrl->iwm_latches &= ~(1 << latch);
358     }
359 
360     reg = (swimctrl->iwm_latches & 0xc0) >> 5 |
361           (swimctrl->iwm_latches & 0x10) >> 4;
362 
363     switch (reg) {
364     case IWM_READALLONES:
365         value = 0xff;
366         break;
367     default:
368         value = 0;
369         break;
370     }
371 
372     trace_swim_iwmctrl_read(reg, iwm_reg_names[reg], size, value);
373     return value;
374 }
375 
376 static const MemoryRegionOps swimctrl_iwm_ops = {
377     .write = iwmctrl_write,
378     .read = iwmctrl_read,
379     .endianness = DEVICE_BIG_ENDIAN,
380 };
381 
ismctrl_write(void * opaque,hwaddr reg,uint64_t value,unsigned size)382 static void ismctrl_write(void *opaque, hwaddr reg, uint64_t value,
383                           unsigned size)
384 {
385     SWIMCtrl *swimctrl = opaque;
386 
387     reg >>= REG_SHIFT;
388 
389     trace_swim_ismctrl_write(reg, ism_reg_names[reg], size, value);
390 
391     switch (reg) {
392     case SWIM_WRITE_PHASE:
393         swimctrl->swim_phase = value;
394         break;
395     case SWIM_WRITE_MODE0:
396         swimctrl->swim_mode &= ~value;
397         /* Any access to MODE0 register resets PRAM index */
398         swimctrl->pram_idx = 0;
399 
400         if (!(swimctrl->swim_mode & (1 << SWIM_MODE_STATUS_BIT))) {
401             /* Clearing the mode bit switches to IWM mode */
402             swimctrl->mode = SWIM_MODE_IWM;
403             swimctrl->iwm_latches = 0;
404             trace_swim_switch_to_iwm();
405 
406             /* Switch to IWM registers */
407             memory_region_del_subregion(&swimctrl->swim, &swimctrl->ism);
408             memory_region_add_subregion(&swimctrl->swim, 0x0,
409                                         &swimctrl->iwm);
410         }
411         break;
412     case SWIM_WRITE_MODE1:
413         swimctrl->swim_mode |= value;
414         break;
415     case SWIM_WRITE_PARAMETER:
416         swimctrl->pram[swimctrl->pram_idx++] = value;
417         swimctrl->pram_idx &= 0xf;
418         break;
419     case SWIM_WRITE_DATA:
420     case SWIM_WRITE_MARK:
421     case SWIM_WRITE_CRC:
422     case SWIM_WRITE_SETUP:
423         break;
424     }
425 }
426 
ismctrl_read(void * opaque,hwaddr reg,unsigned size)427 static uint64_t ismctrl_read(void *opaque, hwaddr reg, unsigned size)
428 {
429     SWIMCtrl *swimctrl = opaque;
430     uint32_t value = 0;
431 
432     reg >>= REG_SHIFT;
433 
434     switch (reg) {
435     case SWIM_READ_PHASE:
436         value = swimctrl->swim_phase;
437         break;
438     case SWIM_READ_HANDSHAKE:
439         if (swimctrl->swim_phase == SWIM_DRIVE_PRESENT) {
440             /* always answer "no drive present" */
441             value = SWIM_SENSE;
442         }
443         break;
444     case SWIM_READ_PARAMETER:
445         value = swimctrl->pram[swimctrl->pram_idx++];
446         swimctrl->pram_idx &= 0xf;
447         break;
448     case SWIM_READ_STATUS:
449         value = swimctrl->swim_status & ~(1 << SWIM_MODE_STATUS_BIT);
450         if (swimctrl->swim_mode == SWIM_MODE_ISM) {
451             value |= (1 << SWIM_MODE_STATUS_BIT);
452         }
453         break;
454     case SWIM_READ_DATA:
455     case SWIM_READ_MARK:
456     case SWIM_READ_ERROR:
457     case SWIM_READ_SETUP:
458         break;
459     }
460 
461     trace_swim_ismctrl_read(reg, ism_reg_names[reg], size, value);
462     return value;
463 }
464 
465 static const MemoryRegionOps swimctrl_ism_ops = {
466     .write = ismctrl_write,
467     .read = ismctrl_read,
468     .endianness = DEVICE_BIG_ENDIAN,
469 };
470 
sysbus_swim_reset(DeviceState * d)471 static void sysbus_swim_reset(DeviceState *d)
472 {
473     Swim *sys = SWIM(d);
474     SWIMCtrl *ctrl = &sys->ctrl;
475     int i;
476 
477     ctrl->mode = 0;
478     ctrl->iwm_switch = 0;
479     memset(ctrl->iwmregs, 0, sizeof(ctrl->iwmregs));
480 
481     ctrl->swim_phase = 0;
482     ctrl->swim_mode = 0;
483     memset(ctrl->ismregs, 0, sizeof(ctrl->ismregs));
484     for (i = 0; i < SWIM_MAX_FD; i++) {
485         fd_recalibrate(&ctrl->drives[i]);
486     }
487 }
488 
sysbus_swim_init(Object * obj)489 static void sysbus_swim_init(Object *obj)
490 {
491     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
492     Swim *sbs = SWIM(obj);
493     SWIMCtrl *swimctrl = &sbs->ctrl;
494 
495     memory_region_init(&swimctrl->swim, obj, "swim", 0x2000);
496     memory_region_init_io(&swimctrl->iwm, obj, &swimctrl_iwm_ops, swimctrl,
497                           "iwm", 0x2000);
498     memory_region_init_io(&swimctrl->ism, obj, &swimctrl_ism_ops, swimctrl,
499                           "ism", 0x2000);
500     sysbus_init_mmio(sbd, &swimctrl->swim);
501 }
502 
sysbus_swim_realize(DeviceState * dev,Error ** errp)503 static void sysbus_swim_realize(DeviceState *dev, Error **errp)
504 {
505     Swim *sys = SWIM(dev);
506     SWIMCtrl *swimctrl = &sys->ctrl;
507 
508     qbus_init(&swimctrl->bus, sizeof(SWIMBus), TYPE_SWIM_BUS, dev, NULL);
509     swimctrl->bus.ctrl = swimctrl;
510 
511     /* Default register set is IWM */
512     memory_region_add_subregion(&swimctrl->swim, 0x0, &swimctrl->iwm);
513 }
514 
515 static const VMStateDescription vmstate_fdrive = {
516     .name = "fdrive",
517     .version_id = 1,
518     .minimum_version_id = 1,
519     .fields = (const VMStateField[]) {
520         VMSTATE_END_OF_LIST()
521     },
522 };
523 
524 static const VMStateDescription vmstate_swim = {
525     .name = "swim",
526     .version_id = 1,
527     .minimum_version_id = 1,
528     .fields = (const VMStateField[]) {
529         VMSTATE_INT32(mode, SWIMCtrl),
530         /* IWM mode */
531         VMSTATE_INT32(iwm_switch, SWIMCtrl),
532         VMSTATE_UINT8(iwm_latches, SWIMCtrl),
533         VMSTATE_UINT8_ARRAY(iwmregs, SWIMCtrl, 8),
534         /* SWIM mode */
535         VMSTATE_UINT8_ARRAY(ismregs, SWIMCtrl, 16),
536         VMSTATE_UINT8(swim_phase, SWIMCtrl),
537         VMSTATE_UINT8(swim_mode, SWIMCtrl),
538         /* Drives */
539         VMSTATE_STRUCT_ARRAY(drives, SWIMCtrl, SWIM_MAX_FD, 1,
540                              vmstate_fdrive, FDrive),
541         VMSTATE_END_OF_LIST()
542     },
543 };
544 
545 static const VMStateDescription vmstate_sysbus_swim = {
546     .name = "SWIM",
547     .version_id = 1,
548     .fields = (const VMStateField[]) {
549         VMSTATE_STRUCT(ctrl, Swim, 0, vmstate_swim, SWIMCtrl),
550         VMSTATE_END_OF_LIST()
551     }
552 };
553 
sysbus_swim_class_init(ObjectClass * oc,void * data)554 static void sysbus_swim_class_init(ObjectClass *oc, void *data)
555 {
556     DeviceClass *dc = DEVICE_CLASS(oc);
557 
558     dc->realize = sysbus_swim_realize;
559     dc->reset = sysbus_swim_reset;
560     dc->vmsd = &vmstate_sysbus_swim;
561 }
562 
563 static const TypeInfo sysbus_swim_info = {
564     .name          = TYPE_SWIM,
565     .parent        = TYPE_SYS_BUS_DEVICE,
566     .instance_size = sizeof(Swim),
567     .instance_init = sysbus_swim_init,
568     .class_init    = sysbus_swim_class_init,
569 };
570 
swim_register_types(void)571 static void swim_register_types(void)
572 {
573     type_register_static(&sysbus_swim_info);
574     type_register_static(&swim_bus_info);
575     type_register_static(&swim_drive_info);
576 }
577 
578 type_init(swim_register_types)
579