顯示具有 Linux driver 標籤的文章。 顯示所有文章
顯示具有 Linux driver 標籤的文章。 顯示所有文章

2008年4月11日 星期五

bio_endio

void bio_endio(struct bio *bio, unsigned int nbytes, int error);
通知系統 I/O完成
nbytes表示實際傳送的bytes

struct block_device

struct gendisk * bd_disk:
Pointer to gendisk structure of the disk underlying this block device

copy_from_user

mkdev

dev_t MKDEV(unsigned int major, unsigned int minor);
Macro that builds adev_t data item from the major and minor numbers.

2008年3月19日 星期三

sense buffer in scsi

sg_io_hdr_t structure's sbp field:

points to user memory of at least 'mx_sb_len' bytes length where the SCSI sense buffer will be output.

2008年3月13日 星期四

Device driver registration for disk

(1)allocate a gendisk for each disk
The gendisk structure is allocated using alloc_disk by passing minor number
Minor number means the number of partitions. Hence, 1 means no partition
(2)assign a request queue for each gendisk
(3)gendisk structures are registered using add_disk function

2008年3月11日 星期二

struct stat and stat function

#include
#include
struct stat {
dev_t st_dev;
ino_t st_ino;
mode_t st_mode;
nlink_t st_nlink;
uid_t st_uid;
gid_t st_gid;
dev_t st_rdev;
off_t st_size;
time_t st_atime;
time_t st_mtime;
time_t st_ctime;
blksize_t st_blksize;
blkcnt_t st_blocks;
mode_t st_attr;
};

int stat(const char *restrict path, struct stat *restrict buf);
get file status

2008年3月2日 星期日

mptsas

sas driver on linux

mdprobe mptsas

2008年1月31日 星期四

ENOSYS

ENOSYS:
error code

2008年1月15日 星期二

ERR_PTR and IS_ERR

defined in linux/err.h

void *ERR_PTR(long error) :
A function returning a pointer type can return an error value

long IS_ERR(const void *ptr)
test whether a returned pointer is an error code or not:

long PTR_ERR(const void *ptr)
get the actual error code

2008年1月7日 星期一

major number and minor number

type dev_t:
major & minor numbers are store in variable of type dev_t, which is 32bit

device without request queue

Some devices have no real need for a request queue. They can hande requests directly as they are generated.

However, the request queue must still be created. The queue will not be used to handle the actual requests, but it contains other infrastructure needed by the block subsystem

(1) create queue
request_queue_t *blk_alloc_queue(int gfp_mask);

(2) set up the request function
typedef int (make_request_fn) (request_queue_t *q, struct bio *bio);

(3) To arrange for your driver's function to be called
void blk_queue_make_request(request_queue_t *q, make_request_fn *func);

(4) when your driver shuts down, be sure to return the request queue to the system
void blk_put_queue(request_queue_t *queue);

request queue

represented by a pointer to struct request_queue

initialization:
request_queue_t *blk_init_queue(request_fn_proc *request_fn, spinlock_t *lock);
// request_fn is the driver's function which will process requests

remove queue
void blk_cleanup_queue(request_queue_t *q);

Note that neither of these functions is normally called if a "make request" function is being used

find the next request to process with
struct request *elv_next_request(request_queue_t *q);

a request contains a list of BIO structures. iterating through a request's BIOs
struct bio *bio;
rq_for_each_bio(bio, req) {
/* Process this BIO */
}

As your driver performs the transfers described by the BIO structures, it will need to update the kernel on its progress.
int end_that_request_first(struct request *req, int uptodate, int nsectors);

remove request from queue
void blkdev_dequeue_request(struct request *req);
void end_that_request_last(struct request *req);

2008年1月6日 星期日

linux driver command

lsmod 顯示目前已經載入的模組清單

insmod moduleName
load module into kernel
ex: insmod hello.ko

rmmod:
remove module

printk

the message is writed to /var/log/messages

use tail -f /var/log/messages to show log messages

can use dmesg to show latest log messages

ex: printk(KERN_ALERT "hello\n");

create block device driver

example: sbd( simple block driver)
ps: referenc http://lwn.net/Articles/58719/

(1) define a sturcture to represent the disk
static struct sbd_device {
unsigned long size;
spinlock_t lock;
u8 *data;
struct gendisk *gd;
} Device;

(2) disk initializtion
Device.size = nsectors*hardsect_size;
spin_lock_init(&Device.lock);
Device.data = vmalloc(Device.size);
if (Device.data == NULL)
return -ENOMEM;

(3) register with kernel( assignment of a dynamic major number (if requested), and causing the block
driver to show up in /proc/devices.)
major_num = register_blkdev(major_num, "sbd");

(4) gendisk( general disk) initializtion
Device.gd = alloc_disk(16);
Device.gd->major = major_num;
Device.gd->first_minor = 0;
Device.gd->fops = &sbd_ops;
Device.gd->private_data = &Device;
strcpy (Device.gd->disk_name, "sbd0");
set_capacity(Device.gd, nsectors*(hardsect_size/KERNEL_SECTOR_SIZE));

//The fops field is a pointer to the block_device_operations structure
//The private_data field can be used by the driver, so we stick a pointer to our sbd_device structure

(5) set up the request queue
static struct request_queue *Queue;
/* ... */
Queue = blk_init_queue(sbd_request, &Device.lock);
if (Queue == NULL)
goto out;
blk_queue_hardsect_size(Queue, hardsect_size);
Device.gd->queue = Queue;

// sbd_request is the request function
// the lock used by the driver to serialize access to internal resources is the best choice for controlling
access to the request queue as well

(6) add the disk to the system
add_disk(Device.gd);

(7) open and release( ( kept in the block_device_operations structure)
Drivers for real hardware may need to lock and unlock doors, check for media

(8) the request method
static void sbd_request(request_queue_t *q)
{
struct request *req;

while ((req = elv_next_request(q)) != NULL) {
if (! blk_fs_request(req)) {
end_request(req, 0);
continue;
}
sbd_transfer(&Device, req->sector, req->current_nr_sectors,
req->buffer, rq_data_dir(req));
end_request(req, 1);
}
}

// elv_next_request(): getting the first request in the queue. this function does not actually remove the
// request from the queue
// there can be multiple types of requests
// A nonzero return value from the blk_fs_request() macro says "this is a normal filesystem request."
// sbd_transfer(): just a memcpy() with some checking
// rq_data_dir(): A nonzero value (WRITE) indicates that this is a write request
// end_request(): finish processing of this request

(9) ioctl
int sbd_ioctl (struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
long size;
struct hd_geometry geo;

switch(cmd) {
/*
* The only command we need to interpret is HDIO_GETGEO, since
* we can't partition the drive otherwise. We have no real
* geometry, of course, so make something up.
*/
case HDIO_GETGEO:
size = Device.size*(hardsect_size/KERNEL_SECTOR_SIZE);
geo.cylinders = (size & ~0x3f) >> 6;
geo.heads = 4;
geo.sectors = 16;
geo.start = 4;
if (copy_to_user((void *) arg, &geo, sizeof(geo)))
return -EFAULT;
return 0;
}
return -ENOTTY; /* unknown command */
}

open iscsi

start:
rcopen-iscsi start
or
service open-iscsi start

show status:
rcopen-iscsi status
connect to target
iscsiadm -m discovery -t st -p 192.168.111.11
show connected target
iscsiadm -m node
[a3f400] 192.168.111.11:3260,1 iqn.2006-05.net.anything:store0
login
iscsiadm -m node -r a3f400 -l
stop open-iscsi
rcopen-iscsi stop
mount:


run iscsi daemon
/sbin/iscsid -f

loginall
iscsiadm -m node --loginall=all

important macro

#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
return variable whose type is “type” & has member “member”, 
the member is pointed by “ptr”

#define list_entry(ptr, type, member) \
container_of(ptr, type, member)

SG_IO ioctl, sg_io_hdr_t structure and to_scsi_device



evpd(enable vital product data):
the server shall return VPD specified by Page Code when evpd=1

The SG_IO ioctl permits user applications to send SCSI commands to a device

defined in /scsi/sg.h

sg_io_hdr_t structure is the main control structure for the version 3 SCSI generic driver

typedef struct sg_io_hdr
{
int interface_id; /* [i] 'S' (required) */
int dxfer_direction; /* [i] */
unsigned char cmd_len; /* [i] */
unsigned char mx_sb_len; /* [i] */
unsigned short iovec_count; /* [i] */
unsigned int dxfer_len; /* [i] */

// If 'iovec_count' is zero then this value is a pointer to user memory of at least 'dxfer_len' bytes in
// length. If there is a data
//transfer associated with the command then the data will be transferred to or from this user memory.
void * dxferp; /* [i], [*io] */

// This value points to the SCSI command to be executed. The command is assumed to be 'cmd_len'
// bytes long.
unsigned char * cmdp; /* [i], [*i] */

//This value points to user memory of at least 'mx_sb_len' bytes length where the SCSI sense buffer will
//be output. Most successful commands do not output a sense buffer and this will be indicated by
// 'sb_len_wr' being zero
unsigned char * sbp; /* [i], [*o] */

unsigned int timeout; /* [i] unit: millisecs */
unsigned int flags; /* [i] */
int pack_id; /* [i->o] */
void * usr_ptr; /* [i->o] */
unsigned char status; /* [o] */
unsigned char masked_status;/* [o] */
unsigned char msg_status; /* [o] */
unsigned char sb_len_wr; /* [o] */
unsigned short host_status; /* [o] */
unsigned short driver_status;/* [o] */
int resid; /* [o] */
unsigned int duration; /* [o] */
unsigned int info; /* [o] */
} sg_io_hdr_t; /* 64 bytes long (on i386) */

ex:
struct sg_io_hdr io_hdr;
ioctl(fd, SG_IO, &io_hdr)

in scsi_device.h
#define to_scsi_device ( d ) container_of(d, struct scsi_device, sdev_gendev)

unsigned char * cmdp;
ex: Inquiry Command: 0x12

command code:
inquiry 0x12
send diagnostic 1d
receive diagnostic results 1c

page code:
00: Supported vital product data pages
80: Unit Serial Number Page
83: Device Identification
c0: Vendor specific, Physical Device Identification
c1: Vendor specific, Logical Drive Geometry

vpd( vital projuct data) page:
ex:
unit serial number VPD page:


The PAGE LENGTH field specifies the length of the product serial number