Commit b833b481c10cf591b15cc674948cc514e55d3b94

Authored by Stephen Rothwell
Committed by Paul Mackerras
1 parent dd9b67ab37

[POWERPC] iSeries: Move detection of virtual cdroms

Now we will only have entries in the device tree for the actual existing
devices (including their OS/400 properties).  This way viocd.c gets all
the information about the devices from the device tree.

Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
Acked-by: Jens Axboe <jens.axboe@oracle.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>

Showing 6 changed files with 361 additions and 105 deletions Side-by-side Diff

arch/powerpc/kernel/vio.c
... ... @@ -247,9 +247,6 @@
247 247 int err;
248 248 struct device_node *node_vroot;
249 249  
250   - if (firmware_has_feature(FW_FEATURE_ISERIES))
251   - iommu_vio_init();
252   -
253 250 err = bus_register(&vio_bus_type);
254 251 if (err) {
255 252 printk(KERN_ERR "failed to register VIO bus\n");
arch/powerpc/platforms/iseries/Makefile
... ... @@ -7,7 +7,7 @@
7 7 hvcall.o proc.o htab.o iommu.o misc.o irq.o
8 8 obj-$(CONFIG_PCI) += pci.o vpdinfo.o
9 9 obj-$(CONFIG_SMP) += smp.o
10   -obj-$(CONFIG_VIOPATH) += viopath.o
  10 +obj-$(CONFIG_VIOPATH) += viopath.o vio.o
11 11 obj-$(CONFIG_MODULES) += ksyms.o
12 12  
13 13 quiet_cmd_dt_strings = DT_STR $@
arch/powerpc/platforms/iseries/dt.c
... ... @@ -381,10 +381,6 @@
381 381 dt_do_vdevice(dt, "viodasd", reg, i, device_type_block,
382 382 "IBM,iSeries-viodasd", 1);
383 383 reg += HVMAXARCHITECTEDVIRTUALDISKS;
384   -
385   - for (i = 0; i < HVMAXARCHITECTEDVIRTUALCDROMS; i++)
386   - dt_do_vdevice(dt, "viocd", reg, i, device_type_block,
387   - "IBM,iSeries-viocd", 1);
388 384 reg += HVMAXARCHITECTEDVIRTUALCDROMS;
389 385  
390 386 for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++)
arch/powerpc/platforms/iseries/vio.c
  1 +/*
  2 + * Legacy iSeries specific vio initialisation
  3 + * that needs to be built in (not a module).
  4 + *
  5 + * © Copyright 2007 IBM Corporation
  6 + * Author: Stephen Rothwell
  7 + * Some parts collected from various other files
  8 + *
  9 + * This program is free software; you can redistribute it and/or
  10 + * modify it under the terms of the GNU General Public License as
  11 + * published by the Free Software Foundation; either version 2 of the
  12 + * License, or (at your option) any later version.
  13 + *
  14 + * This program is distributed in the hope that it will be useful, but
  15 + * WITHOUT ANY WARRANTY; without even the implied warranty of
  16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17 + * General Public License for more details.
  18 + *
  19 + * You should have received a copy of the GNU General Public License
  20 + * along with this program; if not, write to the Free Software Foundation,
  21 + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  22 + */
  23 +#include <linux/of.h>
  24 +#include <linux/init.h>
  25 +#include <linux/gfp.h>
  26 +#include <linux/completion.h>
  27 +#include <linux/proc_fs.h>
  28 +
  29 +#include <asm/firmware.h>
  30 +#include <asm/iseries/vio.h>
  31 +#include <asm/iseries/iommu.h>
  32 +#include <asm/iseries/hv_types.h>
  33 +#include <asm/iseries/hv_lp_event.h>
  34 +
  35 +#define FIRST_VTY 0
  36 +#define NUM_VTYS 1
  37 +#define FIRST_VSCSI (FIRST_VTY + NUM_VTYS)
  38 +#define NUM_VSCSIS 1
  39 +#define FIRST_VLAN (FIRST_VSCSI + NUM_VSCSIS)
  40 +#define NUM_VLANS HVMAXARCHITECTEDVIRTUALLANS
  41 +#define FIRST_VIODASD (FIRST_VLAN + NUM_VLANS)
  42 +#define NUM_VIODASDS HVMAXARCHITECTEDVIRTUALDISKS
  43 +#define FIRST_VIOCD (FIRST_VIODASD + NUM_VIODASDS)
  44 +#define NUM_VIOCDS HVMAXARCHITECTEDVIRTUALCDROMS
  45 +#define FIRST_VIOTAPE (FIRST_VIOCD + NUM_VIOCDS)
  46 +#define NUM_VIOTAPES HVMAXARCHITECTEDVIRTUALTAPES
  47 +
  48 +static struct property * __init new_property(const char *name, int length,
  49 + const void *value)
  50 +{
  51 + struct property *np = kzalloc(sizeof(*np) + strlen(name) + 1 + length,
  52 + GFP_KERNEL);
  53 +
  54 + if (!np)
  55 + return NULL;
  56 + np->name = (char *)(np + 1);
  57 + np->value = np->name + strlen(name) + 1;
  58 + strcpy(np->name, name);
  59 + memcpy(np->value, value, length);
  60 + np->length = length;
  61 + return np;
  62 +}
  63 +
  64 +static void __init free_property(struct property *np)
  65 +{
  66 + kfree(np);
  67 +}
  68 +
  69 +static struct device_node * __init new_node(const char *path,
  70 + struct device_node *parent)
  71 +{
  72 + struct device_node *np = kzalloc(sizeof(*np), GFP_KERNEL);
  73 +
  74 + if (!np)
  75 + return NULL;
  76 + np->full_name = kmalloc(strlen(path) + 1, GFP_KERNEL);
  77 + if (!np->full_name) {
  78 + kfree(np);
  79 + return NULL;
  80 + }
  81 + strcpy(np->full_name, path);
  82 + of_node_set_flag(np, OF_DYNAMIC);
  83 + kref_init(&np->kref);
  84 + np->parent = of_node_get(parent);
  85 + return np;
  86 +}
  87 +
  88 +static void __init free_node(struct device_node *np)
  89 +{
  90 + struct property *next;
  91 + struct property *prop;
  92 +
  93 + next = np->properties;
  94 + while (next) {
  95 + prop = next;
  96 + next = prop->next;
  97 + free_property(prop);
  98 + }
  99 + of_node_put(np->parent);
  100 + kfree(np->full_name);
  101 + kfree(np);
  102 +}
  103 +
  104 +static int __init add_string_property(struct device_node *np, const char *name,
  105 + const char *value)
  106 +{
  107 + struct property *nprop = new_property(name, strlen(value) + 1, value);
  108 +
  109 + if (!nprop)
  110 + return 0;
  111 + prom_add_property(np, nprop);
  112 + return 1;
  113 +}
  114 +
  115 +static int __init add_raw_property(struct device_node *np, const char *name,
  116 + int length, const void *value)
  117 +{
  118 + struct property *nprop = new_property(name, length, value);
  119 +
  120 + if (!nprop)
  121 + return 0;
  122 + prom_add_property(np, nprop);
  123 + return 1;
  124 +}
  125 +
  126 +struct viocd_waitevent {
  127 + struct completion com;
  128 + int rc;
  129 + u16 sub_result;
  130 +};
  131 +
  132 +struct cdrom_info {
  133 + char rsrcname[10];
  134 + char type[4];
  135 + char model[3];
  136 +};
  137 +
  138 +static void __init handle_cd_event(struct HvLpEvent *event)
  139 +{
  140 + struct viocdlpevent *bevent;
  141 + struct viocd_waitevent *pwe;
  142 +
  143 + if (!event)
  144 + /* Notification that a partition went away! */
  145 + return;
  146 +
  147 + /* First, we should NEVER get an int here...only acks */
  148 + if (hvlpevent_is_int(event)) {
  149 + printk(KERN_WARNING "handle_cd_event: got an unexpected int\n");
  150 + if (hvlpevent_need_ack(event)) {
  151 + event->xRc = HvLpEvent_Rc_InvalidSubtype;
  152 + HvCallEvent_ackLpEvent(event);
  153 + }
  154 + return;
  155 + }
  156 +
  157 + bevent = (struct viocdlpevent *)event;
  158 +
  159 + switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) {
  160 + case viocdgetinfo:
  161 + pwe = (struct viocd_waitevent *)event->xCorrelationToken;
  162 + pwe->rc = event->xRc;
  163 + pwe->sub_result = bevent->sub_result;
  164 + complete(&pwe->com);
  165 + break;
  166 +
  167 + default:
  168 + printk(KERN_WARNING "handle_cd_event: "
  169 + "message with unexpected subtype %0x04X!\n",
  170 + event->xSubtype & VIOMINOR_SUBTYPE_MASK);
  171 + if (hvlpevent_need_ack(event)) {
  172 + event->xRc = HvLpEvent_Rc_InvalidSubtype;
  173 + HvCallEvent_ackLpEvent(event);
  174 + }
  175 + }
  176 +}
  177 +
  178 +static void __init get_viocd_info(struct device_node *vio_root)
  179 +{
  180 + HvLpEvent_Rc hvrc;
  181 + u32 unit;
  182 + struct viocd_waitevent we;
  183 + struct cdrom_info *unitinfo;
  184 + dma_addr_t unitinfo_dmaaddr;
  185 + int ret;
  186 +
  187 + ret = viopath_open(viopath_hostLp, viomajorsubtype_cdio, 2);
  188 + if (ret) {
  189 + printk(KERN_WARNING
  190 + "get_viocd_info: error opening path to host partition %d\n",
  191 + viopath_hostLp);
  192 + return;
  193 + }
  194 +
  195 + /* Initialize our request handler */
  196 + vio_setHandler(viomajorsubtype_cdio, handle_cd_event);
  197 +
  198 + unitinfo = iseries_hv_alloc(
  199 + sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS,
  200 + &unitinfo_dmaaddr, GFP_ATOMIC);
  201 + if (!unitinfo) {
  202 + printk(KERN_WARNING
  203 + "get_viocd_info: error allocating unitinfo\n");
  204 + goto clear_handler;
  205 + }
  206 +
  207 + memset(unitinfo, 0, sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS);
  208 +
  209 + init_completion(&we.com);
  210 +
  211 + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
  212 + HvLpEvent_Type_VirtualIo,
  213 + viomajorsubtype_cdio | viocdgetinfo,
  214 + HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
  215 + viopath_sourceinst(viopath_hostLp),
  216 + viopath_targetinst(viopath_hostLp),
  217 + (u64)&we, VIOVERSION << 16, unitinfo_dmaaddr, 0,
  218 + sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS, 0);
  219 + if (hvrc != HvLpEvent_Rc_Good) {
  220 + printk(KERN_WARNING
  221 + "get_viocd_info: cdrom error sending event. rc %d\n",
  222 + (int)hvrc);
  223 + goto hv_free;
  224 + }
  225 +
  226 + wait_for_completion(&we.com);
  227 +
  228 + if (we.rc) {
  229 + printk(KERN_WARNING "get_viocd_info: bad rc %d:0x%04X\n",
  230 + we.rc, we.sub_result);
  231 + goto hv_free;
  232 + }
  233 +
  234 + for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALCDROMS) &&
  235 + unitinfo[unit].rsrcname[0]; unit++) {
  236 + struct device_node *np;
  237 + char name[64];
  238 + u32 reg = FIRST_VIOCD + unit;
  239 +
  240 + snprintf(name, sizeof(name), "/vdevice/viocd@%08x", reg);
  241 + np = new_node(name, vio_root);
  242 + if (!np)
  243 + goto hv_free;
  244 + if (!add_string_property(np, "name", "viocd") ||
  245 + !add_string_property(np, "device_type", "block") ||
  246 + !add_string_property(np, "compatible",
  247 + "IBM,iSeries-viocd") ||
  248 + !add_raw_property(np, "reg", sizeof(reg), &reg) ||
  249 + !add_raw_property(np, "linux,unit_address",
  250 + sizeof(unit), &unit) ||
  251 + !add_raw_property(np, "linux,vio_rsrcname",
  252 + sizeof(unitinfo[unit].rsrcname),
  253 + unitinfo[unit].rsrcname) ||
  254 + !add_raw_property(np, "linux,vio_type",
  255 + sizeof(unitinfo[unit].type),
  256 + unitinfo[unit].type) ||
  257 + !add_raw_property(np, "linux,vio_model",
  258 + sizeof(unitinfo[unit].model),
  259 + unitinfo[unit].model))
  260 + goto node_free;
  261 + np->name = of_get_property(np, "name", NULL);
  262 + np->type = of_get_property(np, "device_type", NULL);
  263 + of_attach_node(np);
  264 +#ifdef CONFIG_PROC_DEVICETREE
  265 + if (vio_root->pde) {
  266 + struct proc_dir_entry *ent;
  267 +
  268 + ent = proc_mkdir(strrchr(np->full_name, '/') + 1,
  269 + vio_root->pde);
  270 + if (ent)
  271 + proc_device_tree_add_node(np, ent);
  272 + }
  273 +#endif
  274 + continue;
  275 +
  276 + node_free:
  277 + free_node(np);
  278 + break;
  279 + }
  280 +
  281 + hv_free:
  282 + iseries_hv_free(sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS,
  283 + unitinfo, unitinfo_dmaaddr);
  284 + clear_handler:
  285 + vio_clearHandler(viomajorsubtype_cdio);
  286 + viopath_close(viopath_hostLp, viomajorsubtype_cdio, 2);
  287 +}
  288 +
  289 +static int __init iseries_vio_init(void)
  290 +{
  291 + struct device_node *vio_root;
  292 +
  293 + if (!firmware_has_feature(FW_FEATURE_ISERIES))
  294 + return -ENODEV;
  295 +
  296 + iommu_vio_init();
  297 +
  298 + vio_root = of_find_node_by_path("/vdevice");
  299 + if (!vio_root)
  300 + return -ENODEV;
  301 +
  302 + if (viopath_hostLp == HvLpIndexInvalid) {
  303 + vio_set_hostlp();
  304 + /* If we don't have a host, bail out */
  305 + if (viopath_hostLp == HvLpIndexInvalid)
  306 + goto put_node;
  307 + }
  308 +
  309 + get_viocd_info(vio_root);
  310 +
  311 + return 0;
  312 +
  313 + put_node:
  314 + of_node_put(vio_root);
  315 + return -ENODEV;
  316 +}
  317 +arch_initcall(iseries_vio_init);
drivers/cdrom/viocd.c
... ... @@ -56,30 +56,6 @@
56 56 #define VIOCD_KERN_WARNING KERN_WARNING "viocd: "
57 57 #define VIOCD_KERN_INFO KERN_INFO "viocd: "
58 58  
59   -struct viocdlpevent {
60   - struct HvLpEvent event;
61   - u32 reserved;
62   - u16 version;
63   - u16 sub_result;
64   - u16 disk;
65   - u16 flags;
66   - u32 token;
67   - u64 offset; /* On open, max number of disks */
68   - u64 len; /* On open, size of the disk */
69   - u32 block_size; /* Only set on open */
70   - u32 media_size; /* Only set on open */
71   -};
72   -
73   -enum viocdsubtype {
74   - viocdopen = 0x0001,
75   - viocdclose = 0x0002,
76   - viocdread = 0x0003,
77   - viocdwrite = 0x0004,
78   - viocdlockdoor = 0x0005,
79   - viocdgetinfo = 0x0006,
80   - viocdcheck = 0x0007
81   -};
82   -
83 59 /*
84 60 * Should probably make this a module parameter....sigh
85 61 */
86 62  
... ... @@ -131,17 +107,13 @@
131 107 /* These are our internal structures for keeping track of devices */
132 108 static int viocd_numdev;
133 109  
134   -struct cdrom_info {
135   - char rsrcname[10];
136   - char type[4];
137   - char model[3];
138   -};
139   -
140 110 struct disk_info {
141 111 struct gendisk *viocd_disk;
142 112 struct cdrom_device_info viocd_info;
143 113 struct device *dev;
144   - struct cdrom_info unitinfo;
  114 + const char *rsrcname;
  115 + const char *type;
  116 + const char *model;
145 117 };
146 118 static struct disk_info viocd_diskinfo[VIOCD_MAX_CD];
147 119  
... ... @@ -159,9 +131,9 @@
159 131 for (i = 0; i < viocd_numdev; i++) {
160 132 seq_printf(m, "viocd device %d is iSeries resource %10.10s"
161 133 "type %4.4s, model %3.3s\n",
162   - i, viocd_diskinfo[i].unitinfo.rsrcname,
163   - viocd_diskinfo[i].unitinfo.type,
164   - viocd_diskinfo[i].unitinfo.model);
  134 + i, viocd_diskinfo[i].rsrcname,
  135 + viocd_diskinfo[i].type,
  136 + viocd_diskinfo[i].model);
165 137 }
166 138 return 0;
167 139 }
... ... @@ -211,61 +183,6 @@
211 183 .media_changed = viocd_blk_media_changed,
212 184 };
213 185  
214   -/* Get info on CD devices from OS/400 */
215   -static void __init get_viocd_info(void)
216   -{
217   - HvLpEvent_Rc hvrc;
218   - int i;
219   - struct viocd_waitevent we;
220   - struct cdrom_info *viocd_unitinfo;
221   - dma_addr_t unitinfo_dmaaddr;
222   -
223   - viocd_unitinfo = iseries_hv_alloc(
224   - sizeof(*viocd_unitinfo) * VIOCD_MAX_CD,
225   - &unitinfo_dmaaddr, GFP_ATOMIC);
226   - if (viocd_unitinfo == NULL) {
227   - printk(VIOCD_KERN_WARNING "error allocating unitinfo\n");
228   - return;
229   - }
230   -
231   - memset(viocd_unitinfo, 0, sizeof(*viocd_unitinfo) * VIOCD_MAX_CD);
232   -
233   - init_completion(&we.com);
234   -
235   - hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
236   - HvLpEvent_Type_VirtualIo,
237   - viomajorsubtype_cdio | viocdgetinfo,
238   - HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
239   - viopath_sourceinst(viopath_hostLp),
240   - viopath_targetinst(viopath_hostLp),
241   - (u64)&we, VIOVERSION << 16, unitinfo_dmaaddr, 0,
242   - sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, 0);
243   - if (hvrc != HvLpEvent_Rc_Good) {
244   - printk(VIOCD_KERN_WARNING "cdrom error sending event. rc %d\n",
245   - (int)hvrc);
246   - goto error_ret;
247   - }
248   -
249   - wait_for_completion(&we.com);
250   -
251   - if (we.rc) {
252   - const struct vio_error_entry *err =
253   - vio_lookup_rc(viocd_err_table, we.sub_result);
254   - printk(VIOCD_KERN_WARNING "bad rc %d:0x%04X on getinfo: %s\n",
255   - we.rc, we.sub_result, err->msg);
256   - goto error_ret;
257   - }
258   -
259   - for (i = 0; (i < VIOCD_MAX_CD) && viocd_unitinfo[i].rsrcname[0]; i++) {
260   - viocd_diskinfo[viocd_numdev].unitinfo = viocd_unitinfo[i];
261   - viocd_numdev++;
262   - }
263   -
264   -error_ret:
265   - iseries_hv_free(sizeof(*viocd_unitinfo) * VIOCD_MAX_CD,
266   - viocd_unitinfo, unitinfo_dmaaddr);
267   -}
268   -
269 186 static int viocd_open(struct cdrom_device_info *cdi, int purpose)
270 187 {
271 188 struct disk_info *diskinfo = cdi->handle;
... ... @@ -576,7 +493,6 @@
576 493 bevent->block_size / 512);
577 494 }
578 495 /* FALLTHROUGH !! */
579   - case viocdgetinfo:
580 496 case viocdlockdoor:
581 497 pwe = (struct viocd_waitevent *)event->xCorrelationToken;
582 498 return_complete:
583 499  
584 500  
585 501  
586 502  
587 503  
588 504  
589 505  
... ... @@ -660,22 +576,30 @@
660 576 int deviceno;
661 577 struct disk_info *d;
662 578 struct cdrom_device_info *c;
663   - struct cdrom_info *ci;
664 579 struct request_queue *q;
  580 + struct device_node *node = vdev->dev.archdata.of_node;
665 581  
666 582 deviceno = vdev->unit_address;
667   - if (deviceno >= viocd_numdev)
  583 + if (deviceno > VIOCD_MAX_CD)
668 584 return -ENODEV;
  585 + if (!node)
  586 + return -ENODEV;
669 587  
  588 + if (deviceno >= viocd_numdev)
  589 + viocd_numdev = deviceno + 1;
  590 +
670 591 d = &viocd_diskinfo[deviceno];
  592 + d->rsrcname = of_get_property(node, "linux,vio_rsrcname", NULL);
  593 + d->type = of_get_property(node, "linux,vio_type", NULL);
  594 + d->model = of_get_property(node, "linux,vio_model", NULL);
  595 +
671 596 c = &d->viocd_info;
672   - ci = &d->unitinfo;
673 597  
674 598 c->ops = &viocd_dops;
675 599 c->speed = 4;
676 600 c->capacity = 1;
677 601 c->handle = d;
678   - c->mask = ~find_capability(ci->type);
  602 + c->mask = ~find_capability(d->type);
679 603 sprintf(c->name, VIOCD_DEVICE "%c", 'a' + deviceno);
680 604  
681 605 if (register_cdrom(c) != 0) {
... ... @@ -685,7 +609,7 @@
685 609 }
686 610 printk(VIOCD_KERN_INFO "cd %s is iSeries resource %10.10s "
687 611 "type %4.4s, model %3.3s\n",
688   - c->name, ci->rsrcname, ci->type, ci->model);
  612 + c->name, d->rsrcname, d->type, d->model);
689 613 q = blk_init_queue(do_viocd_request, &viocd_reqlock);
690 614 if (q == NULL) {
691 615 printk(VIOCD_KERN_WARNING "Cannot allocate queue for %s!\n",
... ... @@ -793,8 +717,6 @@
793 717  
794 718 /* Initialize our request handler */
795 719 vio_setHandler(viomajorsubtype_cdio, vio_handle_cd_event);
796   -
797   - get_viocd_info();
798 720  
799 721 spin_lock_init(&viocd_reqlock);
800 722  
include/asm-powerpc/iseries/vio.h
... ... @@ -51,6 +51,30 @@
51 51 */
52 52 #define VIO_MAX_SUBTYPES 8
53 53  
  54 +struct viocdlpevent {
  55 + struct HvLpEvent event;
  56 + u32 reserved;
  57 + u16 version;
  58 + u16 sub_result;
  59 + u16 disk;
  60 + u16 flags;
  61 + u32 token;
  62 + u64 offset; /* On open, max number of disks */
  63 + u64 len; /* On open, size of the disk */
  64 + u32 block_size; /* Only set on open */
  65 + u32 media_size; /* Only set on open */
  66 +};
  67 +
  68 +enum viocdsubtype {
  69 + viocdopen = 0x0001,
  70 + viocdclose = 0x0002,
  71 + viocdread = 0x0003,
  72 + viocdwrite = 0x0004,
  73 + viocdlockdoor = 0x0005,
  74 + viocdgetinfo = 0x0006,
  75 + viocdcheck = 0x0007
  76 +};
  77 +
54 78 /*
55 79 * Each subtype can register a handler to process their events.
56 80 * The handler must have this interface.