Skip to content

Commit

Permalink
[POWERPC] iSeries: Move detection of virtual tapes
Browse files Browse the repository at this point in the history
Now we will only have entries in the device tree for the actual existing
devices (including their OS/400 properties).  This way viotape.c gets
all the information about the devices from the device tree.

Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
Signed-off-by: Paul Mackerras <paulus@samba.org>
  • Loading branch information
Stephen Rothwell authored and Paul Mackerras committed Oct 11, 2007
1 parent b833b48 commit 7465ce0
Show file tree
Hide file tree
Showing 4 changed files with 192 additions and 129 deletions.
7 changes: 0 additions & 7 deletions arch/powerpc/platforms/iseries/dt.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ static char __initdata device_type_memory[] = "memory";
static char __initdata device_type_serial[] = "serial";
static char __initdata device_type_network[] = "network";
static char __initdata device_type_block[] = "block";
static char __initdata device_type_byte[] = "byte";
static char __initdata device_type_pci[] = "pci";
static char __initdata device_type_vdevice[] = "vdevice";
static char __initdata device_type_vscsi[] = "vscsi";
Expand Down Expand Up @@ -380,12 +379,6 @@ static void __init dt_vdevices(struct iseries_flat_dt *dt)
for (i = 0; i < HVMAXARCHITECTEDVIRTUALDISKS; i++)
dt_do_vdevice(dt, "viodasd", reg, i, device_type_block,
"IBM,iSeries-viodasd", 1);
reg += HVMAXARCHITECTEDVIRTUALDISKS;
reg += HVMAXARCHITECTEDVIRTUALCDROMS;

for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++)
dt_do_vdevice(dt, "viotape", reg, i, device_type_byte,
"IBM,iSeries-viotape", 1);

dt_end_node(dt);
}
Expand Down
149 changes: 133 additions & 16 deletions arch/powerpc/platforms/iseries/vio.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@
#define FIRST_VIOTAPE (FIRST_VIOCD + NUM_VIOCDS)
#define NUM_VIOTAPES HVMAXARCHITECTEDVIRTUALTAPES

struct vio_waitevent {
struct completion com;
int rc;
u16 sub_result;
};

struct vio_resource {
char rsrcname[10];
char type[4];
char model[3];
};

static struct property * __init new_property(const char *name, int length,
const void *value)
{
Expand Down Expand Up @@ -123,22 +135,10 @@ static int __init add_raw_property(struct device_node *np, const char *name,
return 1;
}

struct viocd_waitevent {
struct completion com;
int rc;
u16 sub_result;
};

struct cdrom_info {
char rsrcname[10];
char type[4];
char model[3];
};

static void __init handle_cd_event(struct HvLpEvent *event)
{
struct viocdlpevent *bevent;
struct viocd_waitevent *pwe;
struct vio_waitevent *pwe;

if (!event)
/* Notification that a partition went away! */
Expand All @@ -158,7 +158,7 @@ static void __init handle_cd_event(struct HvLpEvent *event)

switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) {
case viocdgetinfo:
pwe = (struct viocd_waitevent *)event->xCorrelationToken;
pwe = (struct vio_waitevent *)event->xCorrelationToken;
pwe->rc = event->xRc;
pwe->sub_result = bevent->sub_result;
complete(&pwe->com);
Expand All @@ -179,8 +179,8 @@ static void __init get_viocd_info(struct device_node *vio_root)
{
HvLpEvent_Rc hvrc;
u32 unit;
struct viocd_waitevent we;
struct cdrom_info *unitinfo;
struct vio_waitevent we;
struct vio_resource *unitinfo;
dma_addr_t unitinfo_dmaaddr;
int ret;

Expand Down Expand Up @@ -286,6 +286,122 @@ static void __init get_viocd_info(struct device_node *vio_root)
viopath_close(viopath_hostLp, viomajorsubtype_cdio, 2);
}

/* Handle interrupt events for tape */
static void __init handle_tape_event(struct HvLpEvent *event)
{
struct vio_waitevent *we;
struct viotapelpevent *tevent = (struct viotapelpevent *)event;

if (event == NULL)
/* Notification that a partition went away! */
return;

we = (struct vio_waitevent *)event->xCorrelationToken;
switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) {
case viotapegetinfo:
we->rc = tevent->sub_type_result;
complete(&we->com);
break;
default:
printk(KERN_WARNING "handle_tape_event: weird ack\n");
}
}

static void __init get_viotape_info(struct device_node *vio_root)
{
HvLpEvent_Rc hvrc;
u32 unit;
struct vio_resource *unitinfo;
dma_addr_t unitinfo_dmaaddr;
size_t len = sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALTAPES;
struct vio_waitevent we;
int ret;

ret = viopath_open(viopath_hostLp, viomajorsubtype_tape, 2);
if (ret) {
printk(KERN_WARNING "get_viotape_info: "
"error on viopath_open to hostlp %d\n", ret);
return;
}

vio_setHandler(viomajorsubtype_tape, handle_tape_event);

unitinfo = iseries_hv_alloc(len, &unitinfo_dmaaddr, GFP_ATOMIC);
if (!unitinfo)
goto clear_handler;

memset(unitinfo, 0, len);

hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
HvLpEvent_Type_VirtualIo,
viomajorsubtype_tape | viotapegetinfo,
HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
viopath_sourceinst(viopath_hostLp),
viopath_targetinst(viopath_hostLp),
(u64)(unsigned long)&we, VIOVERSION << 16,
unitinfo_dmaaddr, len, 0, 0);
if (hvrc != HvLpEvent_Rc_Good) {
printk(KERN_WARNING "get_viotape_info: hv error on op %d\n",
(int)hvrc);
goto hv_free;
}

wait_for_completion(&we.com);

for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALTAPES) &&
unitinfo[unit].rsrcname[0]; unit++) {
struct device_node *np;
char name[64];
u32 reg = FIRST_VIOTAPE + unit;

snprintf(name, sizeof(name), "/vdevice/viotape@%08x", reg);
np = new_node(name, vio_root);
if (!np)
goto hv_free;
if (!add_string_property(np, "name", "viotape") ||
!add_string_property(np, "device_type", "byte") ||
!add_string_property(np, "compatible",
"IBM,iSeries-viotape") ||
!add_raw_property(np, "reg", sizeof(reg), &reg) ||
!add_raw_property(np, "linux,unit_address",
sizeof(unit), &unit) ||
!add_raw_property(np, "linux,vio_rsrcname",
sizeof(unitinfo[unit].rsrcname),
unitinfo[unit].rsrcname) ||
!add_raw_property(np, "linux,vio_type",
sizeof(unitinfo[unit].type),
unitinfo[unit].type) ||
!add_raw_property(np, "linux,vio_model",
sizeof(unitinfo[unit].model),
unitinfo[unit].model))
goto node_free;
np->name = of_get_property(np, "name", NULL);
np->type = of_get_property(np, "device_type", NULL);
of_attach_node(np);
#ifdef CONFIG_PROC_DEVICETREE
if (vio_root->pde) {
struct proc_dir_entry *ent;

ent = proc_mkdir(strrchr(np->full_name, '/') + 1,
vio_root->pde);
if (ent)
proc_device_tree_add_node(np, ent);
}
#endif
continue;

node_free:
free_node(np);
break;
}

hv_free:
iseries_hv_free(len, unitinfo, unitinfo_dmaaddr);
clear_handler:
vio_clearHandler(viomajorsubtype_tape);
viopath_close(viopath_hostLp, viomajorsubtype_tape, 2);
}

static int __init iseries_vio_init(void)
{
struct device_node *vio_root;
Expand All @@ -307,6 +423,7 @@ static int __init iseries_vio_init(void)
}

get_viocd_info(vio_root);
get_viotape_info(vio_root);

return 0;

Expand Down
124 changes: 18 additions & 106 deletions drivers/char/viotape.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,47 +92,6 @@ struct viot_devinfo_struct {
#define VIOTAPOP_SETPART 14
#define VIOTAPOP_UNLOAD 15

struct viotapelpevent {
struct HvLpEvent event;
u32 reserved;
u16 version;
u16 sub_type_result;
u16 tape;
u16 flags;
u32 token;
u64 len;
union {
struct {
u32 tape_op;
u32 count;
} op;
struct {
u32 type;
u32 resid;
u32 dsreg;
u32 gstat;
u32 erreg;
u32 file_no;
u32 block_no;
} get_status;
struct {
u32 block_no;
} get_pos;
} u;
};

enum viotapesubtype {
viotapeopen = 0x0001,
viotapeclose = 0x0002,
viotaperead = 0x0003,
viotapewrite = 0x0004,
viotapegetinfo = 0x0005,
viotapeop = 0x0006,
viotapegetpos = 0x0007,
viotapesetpos = 0x0008,
viotapegetstatus = 0x0009
};

enum viotaperc {
viotape_InvalidRange = 0x0601,
viotape_InvalidToken = 0x0602,
Expand Down Expand Up @@ -223,14 +182,11 @@ static const struct vio_error_entry viotape_err_table[] = {
#define VIOT_WRITING 2

/* Our info on the tapes */
struct tape_descr {
char rsrcname[10];
char type[4];
char model[3];
};

static struct tape_descr *viotape_unitinfo;
static dma_addr_t viotape_unitinfo_token;
static struct {
const char *rsrcname;
const char *type;
const char *model;
} viotape_unitinfo[VIOTAPE_MAX_TAPE];

static struct mtget viomtget[VIOTAPE_MAX_TAPE];

Expand Down Expand Up @@ -381,53 +337,6 @@ int tape_rc_to_errno(int tape_rc, char *operation, int tapeno)
return -err->errno;
}

/* Get info on all tapes from OS/400 */
static int get_viotape_info(void)
{
HvLpEvent_Rc hvrc;
int i;
size_t len = sizeof(*viotape_unitinfo) * VIOTAPE_MAX_TAPE;
struct op_struct *op = get_op_struct();

if (op == NULL)
return -ENOMEM;

viotape_unitinfo = iseries_hv_alloc(len, &viotape_unitinfo_token,
GFP_ATOMIC);
if (viotape_unitinfo == NULL) {
free_op_struct(op);
return -ENOMEM;
}

memset(viotape_unitinfo, 0, len);

hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp,
HvLpEvent_Type_VirtualIo,
viomajorsubtype_tape | viotapegetinfo,
HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
viopath_sourceinst(viopath_hostLp),
viopath_targetinst(viopath_hostLp),
(u64) (unsigned long) op, VIOVERSION << 16,
viotape_unitinfo_token, len, 0, 0);
if (hvrc != HvLpEvent_Rc_Good) {
printk(VIOTAPE_KERN_WARN "hv error on op %d\n",
(int)hvrc);
free_op_struct(op);
return -EIO;
}

wait_for_completion(&op->com);

free_op_struct(op);

for (i = 0;
((i < VIOTAPE_MAX_TAPE) && (viotape_unitinfo[i].rsrcname[0]));
i++)
viotape_numdev++;
return 0;
}


/* Write */
static ssize_t viotap_write(struct file *file, const char *buf,
size_t count, loff_t * ppos)
Expand Down Expand Up @@ -899,7 +808,6 @@ static void vioHandleTapeEvent(struct HvLpEvent *event)
tapeminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK;
op = (struct op_struct *)event->xCorrelationToken;
switch (tapeminor) {
case viotapegetinfo:
case viotapeopen:
case viotapeclose:
op->rc = tevent->sub_type_result;
Expand Down Expand Up @@ -942,11 +850,23 @@ static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id)
{
int i = vdev->unit_address;
int j;
struct device_node *node = vdev->dev.archdata.of_node;

if (i >= viotape_numdev)
if (i > VIOTAPE_MAX_TAPE)
return -ENODEV;
if (!node)
return -ENODEV;

if (i >= viotape_numdev)
viotape_numdev = i + 1;

tape_device[i] = &vdev->dev;
viotape_unitinfo[i].rsrcname = of_get_property(node,
"linux,vio_rsrcname", NULL);
viotape_unitinfo[i].type = of_get_property(node, "linux,vio_type",
NULL);
viotape_unitinfo[i].model = of_get_property(node, "linux,vio_model",
NULL);

state[i].cur_part = 0;
for (j = 0; j < MAX_PARTITIONS; ++j)
Expand Down Expand Up @@ -1044,11 +964,6 @@ int __init viotap_init(void)
goto unreg_chrdev;
}

if ((ret = get_viotape_info()) < 0) {
printk(VIOTAPE_KERN_WARN "Unable to obtain virtual device information");
goto unreg_class;
}

ret = vio_register_driver(&viotape_driver);
if (ret)
goto unreg_class;
Expand Down Expand Up @@ -1102,9 +1017,6 @@ static void __exit viotap_exit(void)
vio_unregister_driver(&viotape_driver);
class_destroy(tape_class);
unregister_chrdev(VIOTAPE_MAJOR, "viotape");
if (viotape_unitinfo)
iseries_hv_free(sizeof(viotape_unitinfo[0]) * VIOTAPE_MAX_TAPE,
viotape_unitinfo, viotape_unitinfo_token);
viopath_close(viopath_hostLp, viomajorsubtype_tape, VIOTAPE_MAXREQ + 2);
vio_clearHandler(viomajorsubtype_tape);
clear_op_struct_pool();
Expand Down
Loading

0 comments on commit 7465ce0

Please sign in to comment.