/*
 * Copyright (C) 2000-2003 ASANO Masahiro
 */

#include "def.h"

#define __KERNEL__
#include <linux/blkdev.h>

addr_t print_blk_dev_struct();
addr_t print_request_queue();
addr_t print_request();

void
prhead_blk_dev_struct()
{
	mprintf(SPTR " DEV " SPTR " " SPTR "\n", "ADDR", "QUEUE", "DATA");
}

addr_t
print_blk_dev_struct(addr, n, full)
	addr_t addr;
	int n;
	int full;
{
	struct blk_dev_struct bd;

	if (n >= 0) {
		addr += sizeof(bd) * n;
	}
	memread(addr, sizeof(bd), &bd, "blk_dev_struct");
	if (bd.queue == NULL && bd.data == NULL) {
		int i;
		char *p;
		for (i = 0, p = (char *)&bd; i < sizeof(&bd) && *p == 0; i++, p++)
			;
		if (i == sizeof(&bd))
			return -1;
	}

	mprintf(FPTR " ", addr);
	if (n >= 0) {
		mprintf("%3d ", n);
	} else {
		mprintf("  - ");
	}
	mprintf(FPTR " " FPTR "\n", bd.queue, bd.data);
	if (full) {
		print_request_queue(addr, 1);
	}
	return 0;
}

addr_t
print_request_queue(addr, full)
	addr_t addr;
	int full;
{
	struct request_queue rq;
	const char *p;
	addr_t req;

	memread(addr, sizeof(rq), &rq, "request_queue");

	mprintf("queue_head:        " FPTR "  " FPTR "\n",
		rq.queue_head.next, rq.queue_head.prev);

	mprintf("elevator.elevator_merge_fn:          " FPTR "  %s\n",
		rq.elevator.elevator_merge_fn,
		(p = getsymstr_func((addr_t)rq.elevator.elevator_merge_fn))? p: "");
#if SUBLEVEL<18
	/* stock 2.4.19 have this */
	/* but Red Hat 8.0 linux-2.4.18-14 does not have it */
	mprintf("elevator.elevator_merge_cleanup_fn:  " FPTR "  %s\n",
		rq.elevator.elevator_merge_cleanup_fn,
		(p = getsymstr_func((addr_t)rq.elevator.elevator_merge_cleanup_fn))? p: "");
#endif
	mprintf("elevator.elevator_merge_req_fn:      " FPTR "  %s\n",
		rq.elevator.elevator_merge_req_fn,
		(p = getsymstr_func((addr_t)rq.elevator.elevator_merge_req_fn))? p: "");
	mprintf("request_fn:        " FPTR "  %s\n", rq.request_fn,
		(p = getsymstr_func((addr_t)rq.request_fn))? p: "");
	mprintf("back_merge_fn:     " FPTR "  %s\n", rq.back_merge_fn,
		(p = getsymstr_func((addr_t)rq.back_merge_fn))? p: "");
	mprintf("front_merge_fn:    " FPTR "  %s\n", rq.front_merge_fn,
		(p = getsymstr_func((addr_t)rq.front_merge_fn))? p: "");
	mprintf("merge_requests_fn: " FPTR "  %s\n", rq.merge_requests_fn,
		(p = getsymstr_func((addr_t)rq.merge_requests_fn))? p: "");
	mprintf("make_request_fn:   " FPTR "  %s\n", rq.make_request_fn,
		(p = getsymstr_func((addr_t)rq.make_request_fn))? p: "");
	mprintf("plug_device_fn:    " FPTR "  %s\n", rq.plug_device_fn,
		(p = getsymstr_func((addr_t)rq.plug_device_fn))? p: "");
	mprintf("queuedata:         " FPTR "\n", rq.queuedata);

	mprintf("plug_tq.list:      " FPTR "  " FPTR "\n",
					rq.plug_tq.list.next,
					rq.plug_tq.list.prev);
	mprintf("plug_tq.sync:      %lx\n", rq.plug_tq.sync);
	mprintf("plug_tq.routine:   " FPTR "  %s\n", rq.plug_tq.routine,
		(p = getsymstr_func((addr_t)rq.plug_tq.routine))? p: "");
	mprintf("plug_tq.data:      " FPTR "\n", rq.plug_tq.data);

	mprintf("plugged:           %x\n", rq.plugged);
	mprintf("head_active:       %x\n", rq.head_active);

	if (full) {
		req = (addr_t) rq.queue_head.next;
		while (req && req != (addr_t) &((struct request_queue *)addr)->queue_head) {
			req = print_request(addr);
		}
	}

	return 0;
}

addr_t
print_request(addr)
	addr_t addr;
{
	struct request req;

	memread(addr, sizeof(req), &req, "request");
	mprintf(FPTR " ", addr);
	mprintf("%04x %x %5lx %5lx " FPTR " " FPTR " " FPTR "\n", req.rq_dev, req.cmd, req.sector, req.nr_sectors, req.buffer, req.bh, req.q);

	return (addr_t) req.queue.next;
}
