diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-06-19 22:45:37 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-06-19 22:45:37 +0000 |
commit | 6d403070f28cd44860fdb3a53be5da0275c65cf4 (patch) | |
tree | 0d0e7fe7b5fb7568d19e11d7d862b77a866ce081 /drivers/scsi/sg.c | |
parent | ecf1bf5f6c2e668d03b0a9fb026db7aa41e292e1 (diff) |
Merge with 2.4.0-test1-ac21 + pile of MIPS cleanups to make merging
possible. Chainsawed RM200 kernel to compile again. Jazz machine
status unknown.
Diffstat (limited to 'drivers/scsi/sg.c')
-rw-r--r-- | drivers/scsi/sg.c | 458 |
1 files changed, 265 insertions, 193 deletions
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 4fca4d14d..71b93e379 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -17,8 +17,8 @@ * any later version. * */ - static char * sg_version_str = "Version: 3.1.13 (20000323)"; - static int sg_version_num = 30113; /* 2 digits for each component */ + static char * sg_version_str = "Version: 3.1.15 (20000528)"; + static int sg_version_num = 30115; /* 2 digits for each component */ /* * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes: * - scsi logging is available via SCSI_LOG_TIMEOUT macros. First @@ -113,7 +113,8 @@ static void sg_detach(Scsi_Device *); static Scsi_Cmnd * dummy_cmdp = 0; /* only used for sizeof */ -static rwlock_t sg_dev_arr_lock = RW_LOCK_UNLOCKED; +static rwlock_t sg_dev_arr_lock = RW_LOCK_UNLOCKED; /* Also used to lock + file descriptor list for device */ struct Scsi_Device_Template sg_template = { @@ -155,7 +156,7 @@ typedef struct sg_request /* SG_MAX_QUEUE requests outstanding per file */ char res_used; /* 1 -> using reserve buffer, 0 -> not ... */ char orphan; /* 1 -> drop on sight, 0 -> normal */ char sg_io_owned; /* 1 -> packet belongs to SG_IO */ - char done; /* 1 -> bh handler done, 0 -> prior to bh */ + char done; /* 0->before bh, 1->before read, 2->read */ } Sg_request; /* 168 bytes long on i386 */ typedef struct sg_fd /* holds the state of a file descriptor */ @@ -163,6 +164,7 @@ typedef struct sg_fd /* holds the state of a file descriptor */ struct sg_fd * nextfp; /* NULL when last opened fd on this device */ struct sg_device * parentdp; /* owning device */ wait_queue_head_t read_wait; /* queue read until command done */ + rwlock_t rq_list_lock; /* protect access to list in req_arr */ int timeout; /* defaults to SG_DEFAULT_TIMEOUT */ Sg_scatter_hold reserve; /* buffer held for this file descriptor */ unsigned save_scat_len; /* original length of trunc. scat. element */ @@ -176,7 +178,7 @@ typedef struct sg_fd /* holds the state of a file descriptor */ char cmd_q; /* 1 -> allow command queuing, 0 -> don't */ char next_cmd_len; /* 0 -> automatic (def), >0 -> use on next write() */ char keep_orphan; /* 0 -> drop orphan (def), 1 -> keep for read() */ -} Sg_fd; /* 2760 bytes long on i386 */ +} Sg_fd; /* 2768 bytes long on i386 */ typedef struct sg_device /* holds the state of each scsi generic device */ { @@ -189,7 +191,7 @@ typedef struct sg_device /* holds the state of each scsi generic device */ char exclude; /* opened for exclusive access */ char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */ char detached; /* 0->attached, 1->detached pending removal */ -} Sg_device; /* 40 bytes long on i386 */ +} Sg_device; /* 44 bytes long on i386 */ static int sg_fasync(int fd, struct file * filp, int mode); @@ -222,11 +224,11 @@ static char * sg_low_malloc(int rqSz, int lowDma, int mem_src, static void sg_low_free(char * buff, int size, int mem_src); static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev); static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp); -static Sg_request * sg_get_request(const Sg_fd * sfp, int pack_id); +static Sg_request * sg_get_rq_mark(Sg_fd * sfp, int pack_id); static Sg_request * sg_add_request(Sg_fd * sfp); static int sg_remove_request(Sg_fd * sfp, Sg_request * srp); -static int sg_res_in_use(const Sg_fd * sfp); -static int sg_dio_in_use(const Sg_fd * sfp); +static int sg_res_in_use(Sg_fd * sfp); +static int sg_dio_in_use(Sg_fd * sfp); static void sg_clr_scpnt(Scsi_Cmnd * SCpnt); static void sg_shorten_timeout(Scsi_Cmnd * scpnt); static int sg_ms_to_jif(unsigned int msecs); @@ -364,7 +366,7 @@ static ssize_t sg_read(struct file * filp, char * buf, else req_pack_id = old_hdr.pack_id; } - srp = sg_get_request(sfp, req_pack_id); + srp = sg_get_rq_mark(sfp, req_pack_id); if (! srp) { /* now wait on packet to arrive */ if (filp->f_flags & O_NONBLOCK) return -EAGAIN; @@ -372,7 +374,7 @@ static ssize_t sg_read(struct file * filp, char * buf, int dio = sg_dio_in_use(sfp); res = 0; /* following is a macro that beats race condition */ __wait_event_interruptible(sfp->read_wait, - (srp = sg_get_request(sfp, req_pack_id)), + (srp = sg_get_rq_mark(sfp, req_pack_id)), res); if (0 == res) break; @@ -550,7 +552,7 @@ static ssize_t sg_write(struct file * filp, const char * buf, hp->cmd_len = (unsigned char)cmd_size; hp->iovec_count = 0; hp->mx_sb_len = 0; -#if 1 +#if 0 hp->dxfer_direction = SG_DXFER_UNKNOWN; #else if (input_size > 0) @@ -686,7 +688,7 @@ static int sg_common_write(Sg_fd * sfp, Sg_request * srp, srp->data.sglist_len = 0; srp->data.bufflen = 0; srp->data.buffer = NULL; - hp->duration = jiffies; + hp->duration = jiffies; /* unit jiffies now, millisecs after done */ /* Now send everything of to mid-level. The next time we hear about this packet is when sg_cmd_done_bh() is called (i.e. a callback). */ scsi_do_cmd(SCpnt, (void *)cmnd, @@ -703,6 +705,7 @@ static int sg_ioctl(struct inode * inode, struct file * filp, Sg_device * sdp; Sg_fd * sfp; Sg_request * srp; + unsigned long iflags; if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) return -ENXIO; @@ -740,6 +743,7 @@ static int sg_ioctl(struct inode * inode, struct file * filp, return result; /* -ERESTARTSYS because signal hit process */ } } + srp->done = 2; result = sg_new_read(sfp, (char *)arg, size_sg_io_hdr, srp); return (result < 0) ? result : 0; } @@ -794,24 +798,24 @@ static int sg_ioctl(struct inode * inode, struct file * filp, case SG_GET_PACK_ID: result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int)); if (result) return result; - srp = sfp->headrp; - while (srp) { - if (srp->done && (! srp->sg_io_owned)) { + read_lock_irqsave(&sfp->rq_list_lock, iflags); + for (srp = sfp->headrp; srp; srp = srp->nextrp) { + if ((1 == srp->done) && (! srp->sg_io_owned)) { + read_unlock_irqrestore(&sfp->rq_list_lock, iflags); __put_user(srp->header.pack_id, (int *)arg); return 0; } - srp = srp->nextrp; } + read_unlock_irqrestore(&sfp->rq_list_lock, iflags); __put_user(-1, (int *)arg); return 0; case SG_GET_NUM_WAITING: - srp = sfp->headrp; - val = 0; - while (srp) { - if (srp->done && (! srp->sg_io_owned)) + read_lock_irqsave(&sfp->rq_list_lock, iflags); + for (val = 0, srp = sfp->headrp; srp; srp = srp->nextrp) { + if ((1 == srp->done) && (! srp->sg_io_owned)) ++val; - srp = srp->nextrp; } + read_unlock_irqrestore(&sfp->rq_list_lock, iflags); return put_user(val, (int *)arg); case SG_GET_SG_TABLESIZE: return put_user(sdp->sg_tablesize, (int *)arg); @@ -855,16 +859,17 @@ static int sg_ioctl(struct inode * inode, struct file * filp, if (result) return result; else { sg_req_info_t rinfo[SG_MAX_QUEUE]; - Sg_request * srp = sfp->headrp; - for (val = 0; val < SG_MAX_QUEUE; + Sg_request * srp; + read_lock_irqsave(&sfp->rq_list_lock, iflags); + for (srp = sfp->headrp, val = 0; val < SG_MAX_QUEUE; ++val, srp = srp ? srp->nextrp : srp) { memset(&rinfo[val], 0, size_sg_req_info); if (srp) { - rinfo[val].req_state = srp->done ? 2 : 1; + rinfo[val].req_state = srp->done + 1; rinfo[val].problem = srp->header.masked_status & srp->header.host_status & srp->header.driver_status; rinfo[val].duration = srp->done ? - sg_jif_to_ms(srp->header.duration) : + srp->header.duration : sg_jif_to_ms(jiffies - srp->header.duration); rinfo[val].orphan = srp->orphan; rinfo[val].sg_io_owned = srp->sg_io_owned; @@ -872,6 +877,7 @@ static int sg_ioctl(struct inode * inode, struct file * filp, rinfo[val].usr_ptr = srp->header.usr_ptr; } } + read_unlock_irqrestore(&sfp->rq_list_lock, iflags); __copy_to_user((void *)arg, rinfo, size_sg_req_info * SG_MAX_QUEUE); return 0; } @@ -882,8 +888,29 @@ static int sg_ioctl(struct inode * inode, struct file * filp, return -EBUSY; result = get_user(val, (int *)arg); if (result) return result; - /* Don't do anything till scsi mid level visibility */ - return 0; + if (SG_SCSI_RESET_NOTHING == val) + return 0; +#ifdef SCSI_TRY_RESET_DEVICE + switch (val) + { + case SG_SCSI_RESET_DEVICE: + val = SCSI_TRY_RESET_DEVICE; + break; + case SG_SCSI_RESET_BUS: + val = SCSI_TRY_RESET_BUS; + break; + case SG_SCSI_RESET_HOST: + val = SCSI_TRY_RESET_HOST; + break; + default: + return -EINVAL; + } + if(! capable(CAP_SYS_ADMIN)) return -EACCES; + return (scsi_reset_provider(sdp->device, val) == SUCCESS) ? 0 : -EIO; +#else + SCSI_LOG_TIMEOUT(1, printk("sg_ioctl: SG_RESET_SCSI not supported\n")); + result = -EINVAL; +#endif case SCSI_IOCTL_SEND_COMMAND: if (read_only) { unsigned char opcode = WRITE_6; @@ -918,17 +945,19 @@ static unsigned int sg_poll(struct file * filp, poll_table * wait) Sg_fd * sfp; Sg_request * srp; int count = 0; + unsigned long iflags; if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) return POLLERR; poll_wait(filp, &sfp->read_wait, wait); - srp = sfp->headrp; - while (srp) { /* if any read waiting, flag it */ - if ((0 == res) && srp->done && (! srp->sg_io_owned)) + read_lock_irqsave(&sfp->rq_list_lock, iflags); + for (srp = sfp->headrp; srp; srp = srp->nextrp) { + /* if any read waiting, flag it */ + if ((0 == res) && (1 == srp->done) && (! srp->sg_io_owned)) res = POLLIN | POLLRDNORM; ++count; - srp = srp->nextrp; } + read_unlock_irqrestore(&sfp->rq_list_lock, iflags); if (! sfp->cmd_q) { if (0 == count) res |= POLLOUT | POLLWRNORM; @@ -960,11 +989,17 @@ static int sg_fasync(int fd, struct file * filp, int mode) static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt) { int dev = MINOR(SCpnt->request.rq_dev); - Sg_device * sdp; + Sg_device * sdp = NULL; Sg_fd * sfp; Sg_request * srp = NULL; - if (NULL == (sdp = sg_get_dev(dev))) { + read_lock(&sg_dev_arr_lock); + if (sg_dev_arr && (dev >= 0)) { + if (dev < sg_template.dev_max) + sdp = sg_dev_arr[dev]; + } + if (NULL == sdp) { + read_unlock(&sg_dev_arr_lock); SCSI_LOG_TIMEOUT(1, printk("sg...bh: bad args dev=%d\n", dev)); scsi_release_command(SCpnt); SCpnt = NULL; @@ -972,16 +1007,17 @@ static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt) } sfp = sdp->headfp; while (sfp) { - srp = sfp->headrp; - while (srp) { + read_lock(&sfp->rq_list_lock); + for (srp = sfp->headrp; srp; srp = srp->nextrp) { if (SCpnt == srp->my_cmdp) break; - srp = srp->nextrp; } + read_unlock(&sfp->rq_list_lock); if (srp) break; sfp = sfp->nextfp; } + read_unlock(&sg_dev_arr_lock); if (! srp) { SCSI_LOG_TIMEOUT(1, printk("sg...bh: req missing, dev=%d\n", dev)); scsi_release_command(SCpnt); @@ -1001,6 +1037,7 @@ static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt) dev, srp->header.pack_id, (int)SCpnt->result)); srp->header.resid = SCpnt->resid; /* sg_unmap_and(&srp->data, 0); */ /* unmap locked pages a.s.a.p. */ + /* N.B. unit of duration changes here from jiffies to millisecs */ srp->header.duration = sg_jif_to_ms(jiffies - (int)srp->header.duration); if (0 != SCpnt->result) { memcpy(srp->sense_b, SCpnt->sense_buffer, sizeof(srp->sense_b)); @@ -1052,8 +1089,7 @@ static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt) if (sfp && srp) { /* Now wake up any sg_read() that is waiting for this packet. */ wake_up_interruptible(&sfp->read_wait); - if (sfp->async_qp) - kill_fasync(sfp->async_qp, SIGPOLL, POLL_IN); + kill_fasync(&sfp->async_qp, SIGPOLL, POLL_IN); } } @@ -1091,18 +1127,18 @@ static int sg_detect(Scsi_Device * scsidp) static int sg_init() { static int sg_registered = 0; - unsigned long flags = 0; + unsigned long iflags; if ((sg_template.dev_noticed == 0) || sg_dev_arr) return 0; - write_lock_irqsave(&sg_dev_arr_lock, flags); + write_lock_irqsave(&sg_dev_arr_lock, iflags); if(!sg_registered) { if (devfs_register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops)) { printk("Unable to get major %d for generic SCSI device\n", SCSI_GENERIC_MAJOR); - write_unlock_irqrestore(&sg_dev_arr_lock, flags); + write_unlock_irqrestore(&sg_dev_arr_lock, iflags); return 1; } sg_registered++; @@ -1114,11 +1150,11 @@ static int sg_init() sizeof(Sg_device *), GFP_ATOMIC); if (NULL == sg_dev_arr) { printk("sg_init: no space for sg_dev_arr\n"); - write_unlock_irqrestore(&sg_dev_arr_lock, flags); + write_unlock_irqrestore(&sg_dev_arr_lock, iflags); return 1; } memset(sg_dev_arr, 0, sg_template.dev_max * sizeof(Sg_device *)); - write_unlock_irqrestore(&sg_dev_arr_lock, flags); + write_unlock_irqrestore(&sg_dev_arr_lock, iflags); #ifdef CONFIG_PROC_FS sg_proc_init(); #endif /* CONFIG_PROC_FS */ @@ -1149,10 +1185,10 @@ __setup("sg_def_reserved_size=", sg_def_reserved_size_setup); static int sg_attach(Scsi_Device * scsidp) { Sg_device * sdp; - unsigned long flags = 0; + unsigned long iflags; int k; - write_lock_irqsave(&sg_dev_arr_lock, flags); + write_lock_irqsave(&sg_dev_arr_lock, iflags); if (sg_template.nr_dev >= sg_template.dev_max) { /* try to resize */ Sg_device ** tmp_da; int tmp_dev_max = sg_template.nr_dev + SG_DEV_ARR_LUMP; @@ -1161,7 +1197,7 @@ static int sg_attach(Scsi_Device * scsidp) sizeof(Sg_device *), GFP_ATOMIC); if (NULL == tmp_da) { scsidp->attached--; - write_unlock_irqrestore(&sg_dev_arr_lock, flags); + write_unlock_irqrestore(&sg_dev_arr_lock, iflags); printk("sg_attach: device array cannot be resized\n"); return 1; } @@ -1180,7 +1216,7 @@ static int sg_attach(Scsi_Device * scsidp) sdp = NULL; if (NULL == sdp) { scsidp->attached--; - write_unlock_irqrestore(&sg_dev_arr_lock, flags); + write_unlock_irqrestore(&sg_dev_arr_lock, iflags); printk("sg_attach: Sg_device cannot be allocated\n"); return 1; } @@ -1200,7 +1236,7 @@ static int sg_attach(Scsi_Device * scsidp) &sg_fops, NULL); sg_template.nr_dev++; sg_dev_arr[k] = sdp; - write_unlock_irqrestore(&sg_dev_arr_lock, flags); + write_unlock_irqrestore(&sg_dev_arr_lock, iflags); return 0; } @@ -1214,37 +1250,36 @@ static void sg_finish(void) static void sg_detach(Scsi_Device * scsidp) { Sg_device * sdp; - unsigned long flags = 0; + unsigned long iflags; Sg_fd * sfp; Sg_request * srp; int k; if (NULL == sg_dev_arr) return; - write_lock_irqsave(&sg_dev_arr_lock, flags); -/* Need to stop sg_cmd_done_bh() playing with this list during this loop */ + write_lock_irqsave(&sg_dev_arr_lock, iflags); for (k = 0; k < sg_template.dev_max; k++) { sdp = sg_dev_arr[k]; if ((NULL == sdp) || (sdp->device != scsidp)) continue; /* dirty but lowers nesting */ if (sdp->headfp) { - sfp = sdp->headfp; - while (sfp) { - srp = sfp->headrp; - while (srp) { - if (! srp->done) + for (sfp = sdp->headfp; sfp; sfp = sfp->nextfp) { + /* no lock on request list here */ + for (srp = sfp->headrp; srp; srp = srp->nextrp) { + if (! srp->done) { + write_unlock_irqrestore(&sg_dev_arr_lock, iflags); sg_shorten_timeout(srp->my_cmdp); - srp = srp->nextrp; + write_lock_irqsave(&sg_dev_arr_lock, iflags); } - sfp = sfp->nextfp; } - write_unlock_irqrestore(&sg_dev_arr_lock, flags); + } + write_unlock_irqrestore(&sg_dev_arr_lock, iflags); SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d, dirty, sleep(3)\n", k)); scsi_sleep(3); /* sleep 3 jiffies, hoping for timeout to go off */ devfs_unregister (sdp->de); sdp->de = NULL; sdp->detached = 1; - write_lock_irqsave(&sg_dev_arr_lock, flags); + write_lock_irqsave(&sg_dev_arr_lock, iflags); } else { SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d\n", k)); @@ -1259,7 +1294,7 @@ static void sg_detach(Scsi_Device * scsidp) sg_template.dev_noticed--; break; } - write_unlock_irqrestore(&sg_dev_arr_lock, flags); + write_unlock_irqrestore(&sg_dev_arr_lock, iflags); return; } @@ -1277,12 +1312,11 @@ int init_module(void) { void cleanup_module( void) { - scsi_unregister_module(MODULE_SCSI_DEV, &sg_template); - devfs_unregister_chrdev(SCSI_GENERIC_MAJOR, "sg"); - #ifdef CONFIG_PROC_FS sg_proc_cleanup(); #endif /* CONFIG_PROC_FS */ + scsi_unregister_module(MODULE_SCSI_DEV, &sg_template); + devfs_unregister_chrdev(SCSI_GENERIC_MAJOR, "sg"); if(sg_dev_arr != NULL) { /* Really worrying situation of writes still pending and get here */ /* Strategy: shorten timeout on release + wait on detach ... */ @@ -1301,7 +1335,7 @@ extern void scsi_old_times_out (Scsi_Cmnd * SCpnt); /* Can't see clean way to abort a command so shorten timeout to 1 jiffy */ static void sg_shorten_timeout(Scsi_Cmnd * scpnt) -{ /* assumed to be called with sg_dev_arr_lock held */ +{ #if 0 /* scsi_syms.c is very miserly about exported functions */ scsi_delete_timer(scpnt); if (! scpnt) @@ -1313,11 +1347,7 @@ static void sg_shorten_timeout(Scsi_Cmnd * scpnt) scsi_add_timer(scpnt, scpnt->timeout_per_command, scsi_old_times_out); #else - unsigned long flags = 0; - - write_unlock_irqrestore(&sg_dev_arr_lock, flags); scsi_sleep(HZ); /* just sleep 1 second and hope ... */ - write_lock_irqsave(&sg_dev_arr_lock, flags); #endif } @@ -1859,6 +1889,8 @@ static void sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size) Sg_scatter_hold * rsv_schp = &sfp->reserve; SCSI_LOG_TIMEOUT(4, printk("sg_link_reserve: size=%d\n", size)); + /* round request up to next highest SG_SECTOR_SZ byte boundary */ + size = (size + SG_SECTOR_MSK) & (~SG_SECTOR_MSK); if (rsv_schp->k_use_sg > 0) { int k, num; int rem = size; @@ -1921,17 +1953,35 @@ static void sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp) srp->res_used = 0; } -static Sg_request * sg_get_request(const Sg_fd * sfp, int pack_id) +static Sg_request * sg_get_rq_mark(Sg_fd * sfp, int pack_id) { - Sg_request * resp = NULL; + Sg_request * resp; + unsigned long iflags; - resp = sfp->headrp; - while (resp) { /* look for requests that are ready + not SG_IO owned */ - if (resp->done && (! resp->sg_io_owned) && - ((-1 == pack_id) || (resp->header.pack_id == pack_id))) - return resp; - resp = resp->nextrp; + write_lock_irqsave(&sfp->rq_list_lock, iflags); + for (resp = sfp->headrp; resp; resp = resp->nextrp) { + /* look for requests that are ready + not SG_IO owned */ + if ((1 == resp->done) && (! resp->sg_io_owned) && + ((-1 == pack_id) || (resp->header.pack_id == pack_id))) { + resp->done = 2; /* guard against other readers */ + break; + } } + write_unlock_irqrestore(&sfp->rq_list_lock, iflags); + return resp; +} + +static Sg_request * sg_get_nth_request(Sg_fd * sfp, int nth) +{ + Sg_request * resp; + unsigned long iflags; + int k; + + read_lock_irqsave(&sfp->rq_list_lock, iflags); + for (k = 0, resp = sfp->headrp; resp && (k < nth); + ++k, resp = resp->nextrp) + ; + read_unlock_irqrestore(&sfp->rq_list_lock, iflags); return resp; } @@ -1939,46 +1989,45 @@ static Sg_request * sg_get_request(const Sg_fd * sfp, int pack_id) static Sg_request * sg_add_request(Sg_fd * sfp) { int k; - Sg_request * resp = NULL; - Sg_request * rp; + unsigned long iflags; + Sg_request * resp; + Sg_request * rp = sfp->req_arr; + write_lock_irqsave(&sfp->rq_list_lock, iflags); resp = sfp->headrp; - rp = sfp->req_arr; if (! resp) { - resp = rp; - sfp->headrp = resp; + memset(rp, 0, sizeof(Sg_request)); + rp->parentfp = sfp; + resp = rp; + sfp->headrp = resp; } else { if (0 == sfp->cmd_q) resp = NULL; /* command queuing disallowed */ else { - for (k = 0, rp; k < SG_MAX_QUEUE; ++k, ++rp) { + for (k = 0; k < SG_MAX_QUEUE; ++k, ++rp) { if (! rp->parentfp) break; } if (k < SG_MAX_QUEUE) { - while (resp->nextrp) resp = resp->nextrp; - resp->nextrp = rp; - resp = rp; + memset(rp, 0, sizeof(Sg_request)); + rp->parentfp = sfp; + while (resp->nextrp) + resp = resp->nextrp; + resp->nextrp = rp; + resp = rp; } else resp = NULL; } } if (resp) { - resp->parentfp = sfp; resp->nextrp = NULL; - resp->res_used = 0; - resp->orphan = 0; - resp->sg_io_owned = 0; - resp->done = 0; - memset(&resp->data, 0, sizeof(Sg_scatter_hold)); - memset(&resp->header, 0, size_sg_io_hdr); resp->header.duration = jiffies; resp->my_cmdp = NULL; resp->data.kiobp = NULL; - resp->data.mapped = 0; } + write_unlock_irqrestore(&sfp->rq_list_lock, iflags); return resp; } @@ -1987,29 +2036,51 @@ static int sg_remove_request(Sg_fd * sfp, Sg_request * srp) { Sg_request * prev_rp; Sg_request * rp; + unsigned long iflags; + int res = 0; if ((! sfp) || (! srp) || (! sfp->headrp)) - return 0; + return res; + write_lock_irqsave(&sfp->rq_list_lock, iflags); prev_rp = sfp->headrp; if (srp == prev_rp) { - prev_rp->parentfp = NULL; sfp->headrp = prev_rp->nextrp; - return 1; + prev_rp->parentfp = NULL; + res = 1; } - while ((rp = prev_rp->nextrp)) { - if (srp == rp) { - rp->parentfp = NULL; - prev_rp->nextrp = rp->nextrp; - return 1; - } - prev_rp = rp; + else { + while ((rp = prev_rp->nextrp)) { + if (srp == rp) { + prev_rp->nextrp = rp->nextrp; + rp->parentfp = NULL; + res = 1; + break; + } + prev_rp = rp; + } } - return 0; + write_unlock_irqrestore(&sfp->rq_list_lock, iflags); + return res; +} + +static Sg_fd * sg_get_nth_sfp(Sg_device * sdp, int nth) +{ + Sg_fd * resp; + unsigned long iflags; + int k; + + read_lock_irqsave(&sg_dev_arr_lock, iflags); + for (k = 0, resp = sdp->headfp; resp && (k < nth); + ++k, resp = resp->nextfp) + ; + read_unlock_irqrestore(&sg_dev_arr_lock, iflags); + return resp; } static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev) { Sg_fd * sfp; + unsigned long iflags; sfp = (Sg_fd *)sg_low_malloc(sizeof(Sg_fd), 0, SG_HEAP_KMAL, 0); if (! sfp) @@ -2017,6 +2088,7 @@ static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev) memset(sfp, 0, sizeof(Sg_fd)); sfp->fd_mem_src = SG_HEAP_KMAL; init_waitqueue_head(&sfp->read_wait); + sfp->rq_list_lock = RW_LOCK_UNLOCKED; sfp->timeout = SG_DEFAULT_TIMEOUT; sfp->force_packid = SG_DEF_FORCE_PACK_ID; @@ -2025,14 +2097,16 @@ static Sg_fd * sg_add_sfp(Sg_device * sdp, int dev) sfp->cmd_q = SG_DEF_COMMAND_Q; sfp->keep_orphan = SG_DEF_KEEP_ORPHAN; sfp->parentdp = sdp; + write_lock_irqsave(&sg_dev_arr_lock, iflags); if (! sdp->headfp) sdp->headfp = sfp; else { /* add to tail of existing list */ - Sg_fd * pfp = sdp->headfp; - while (pfp->nextfp) - pfp = pfp->nextfp; - pfp->nextfp = sfp; + Sg_fd * pfp = sdp->headfp; + while (pfp->nextfp) + pfp = pfp->nextfp; + pfp->nextfp = sfp; } + write_unlock_irqrestore(&sg_dev_arr_lock, iflags); SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p, m_s=%d\n", sfp, (int)sfp->fd_mem_src)); sg_build_reserve(sfp, sg_big_buff); @@ -2048,36 +2122,41 @@ static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp) int dirty = 0; int res = 0; + /* no lock since not expecting any parallel action on this fd */ srp = sfp->headrp; if (srp) { - while (srp) { - tsrp = srp->nextrp; + while (srp) { + tsrp = srp->nextrp; if (srp->done) sg_finish_rem_req(srp); - else - ++dirty; - srp = tsrp; - } + else + ++dirty; + srp = tsrp; + } } if (0 == dirty) { - Sg_fd * fp; - Sg_fd * prev_fp = sdp->headfp; - - if (sfp == prev_fp) - sdp->headfp = prev_fp->nextfp; - else { - while ((fp = prev_fp->nextfp)) { - if (sfp == fp) { - prev_fp->nextfp = fp->nextfp; - break; - } - prev_fp = fp; - } - } - if (sfp->reserve.bufflen > 0) { + Sg_fd * fp; + Sg_fd * prev_fp; + unsigned long iflags; + + write_lock_irqsave(&sg_dev_arr_lock, iflags); + prev_fp = sdp->headfp; + if (sfp == prev_fp) + sdp->headfp = prev_fp->nextfp; + else { + while ((fp = prev_fp->nextfp)) { + if (sfp == fp) { + prev_fp->nextfp = fp->nextfp; + break; + } + prev_fp = fp; + } + } + write_unlock_irqrestore(&sg_dev_arr_lock, iflags); + if (sfp->reserve.bufflen > 0) { SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp: bufflen=%d, k_use_sg=%d\n", (int)sfp->reserve.bufflen, (int)sfp->reserve.k_use_sg)); - sg_remove_scat(&sfp->reserve); + sg_remove_scat(&sfp->reserve); } sfp->parentdp = NULL; SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp: sfp=0x%p\n", sfp)); @@ -2104,28 +2183,28 @@ SCSI_LOG_TIMEOUT(6, printk("sg_remove_sfp: bufflen=%d, k_use_sg=%d\n", return res; } -static int sg_res_in_use(const Sg_fd * sfp) +static int sg_res_in_use(Sg_fd * sfp) { - const Sg_request * srp = sfp->headrp; + const Sg_request * srp; + unsigned long iflags; - while (srp) { - if (srp->res_used) - return 1; - srp = srp->nextrp; - } - return 0; + read_lock_irqsave(&sfp->rq_list_lock, iflags); + for (srp = sfp->headrp; srp; srp = srp->nextrp) + if (srp->res_used) break; + read_unlock_irqrestore(&sfp->rq_list_lock, iflags); + return srp ? 1 : 0; } -static int sg_dio_in_use(const Sg_fd * sfp) +static int sg_dio_in_use(Sg_fd * sfp) { - const Sg_request * srp = sfp->headrp; + const Sg_request * srp; + unsigned long iflags; - while (srp) { - if ((! srp->done) && srp->data.kiobp) - return 1; - srp = srp->nextrp; - } - return 0; + read_lock_irqsave(&sfp->rq_list_lock, iflags); + for (srp = sfp->headrp; srp; srp = srp->nextrp) + if ((! srp->done) && srp->data.kiobp) break; + read_unlock_irqrestore(&sfp->rq_list_lock, iflags); + return srp ? 1 : 0; } /* If retSzp==NULL want exact size or fail */ @@ -2314,7 +2393,8 @@ static unsigned sg_jif_to_ms(int jifs) } static unsigned char allow_ops[] = {TEST_UNIT_READY, INQUIRY, -READ_CAPACITY, READ_BUFFER, READ_6, READ_10, READ_12}; +READ_CAPACITY, READ_BUFFER, READ_6, READ_10, READ_12, +MODE_SENSE, MODE_SENSE_10}; static int sg_allow_access(unsigned char opcode, char dev_type) { @@ -2331,28 +2411,29 @@ static int sg_allow_access(unsigned char opcode, char dev_type) static int sg_last_dev() -{ /* assumed to be called with sg_dev_arr_lock held */ +{ int k; + unsigned long iflags; - for (k = sg_template.dev_max - 1; k >= 0; --k) { - if (sg_dev_arr[k] && sg_dev_arr[k]->device) - return k + 1; - } - return 0; /* origin 1 */ + read_lock_irqsave(&sg_dev_arr_lock, iflags); + for (k = sg_template.dev_max - 1; k >= 0; --k) + if (sg_dev_arr[k] && sg_dev_arr[k]->device) break; + read_unlock_irqrestore(&sg_dev_arr_lock, iflags); + return k + 1; /* origin 1 */ } static Sg_device * sg_get_dev(int dev) { - Sg_device * sdp; + Sg_device * sdp = NULL; + unsigned long iflags; - if ((NULL == sg_dev_arr) || (dev < 0)) - return NULL; - read_lock(&sg_dev_arr_lock); + if (sg_dev_arr && (dev >= 0)) + { + read_lock_irqsave(&sg_dev_arr_lock, iflags); if (dev < sg_template.dev_max) sdp = sg_dev_arr[dev]; - else - sdp = NULL; - read_unlock(&sg_dev_arr_lock); + read_unlock_irqrestore(&sg_dev_arr_lock, iflags); + } return sdp; } @@ -2429,8 +2510,7 @@ static write_proc_t * sg_proc_leaf_writes[] = { *eof = infofp(buffer, &len, &begin, offset, size); \ if (offset >= (begin + len)) \ return 0; \ - *start = buffer + ((begin > offset) ? \ - (begin - offset) : (offset - begin)); \ + *start = buffer + offset - begin; \ return (size < (begin + len - offset)) ? \ size : begin + len - offset; \ } while(0) @@ -2520,7 +2600,6 @@ static int sg_proc_debug_info(char * buffer, int * len, off_t * begin, PRINT_PROC("sg_dev_arr NULL, driver not initialized\n"); return 1; } - read_lock(&sg_dev_arr_lock); max_dev = sg_last_dev(); PRINT_PROC("dev_max(currently)=%d max_active_device=%d (origin 1)\n", sg_template.dev_max, max_dev); @@ -2528,11 +2607,11 @@ static int sg_proc_debug_info(char * buffer, int * len, off_t * begin, "def_reserved_size=%d\n", scsi_dma_free_sectors, sg_pool_secs_avail, sg_big_buff); for (j = 0; j < max_dev; ++j) { - if ((sdp = sg_dev_arr[j])) { + if ((sdp = sg_get_dev(j))) { Sg_fd * fp; Sg_request * srp; struct scsi_device * scsidp; - int dev, k, blen, usg; + int dev, k, m, blen, usg; if (! (scsidp = sdp->device)) { PRINT_PROC("device %d detached ??\n", j); @@ -2540,48 +2619,45 @@ static int sg_proc_debug_info(char * buffer, int * len, off_t * begin, } dev = MINOR(sdp->i_rdev); - if ((fp = sdp->headfp)) { - PRINT_PROC(" >>> device=%d(sg%d) ", dev, dev); + if (sg_get_nth_sfp(sdp, 0)) { + PRINT_PROC(" >>> device=sg%d ", dev); PRINT_PROC("scsi%d chan=%d id=%d lun=%d em=%d sg_tablesize=%d" " excl=%d\n", scsidp->host->host_no, scsidp->channel, scsidp->id, scsidp->lun, scsidp->host->hostt->emulated, sdp->sg_tablesize, sdp->exclude); } - for (k = 1; fp; fp = fp->nextfp, ++k) { - PRINT_PROC(" FD(%d): timeout=%d bufflen=%d " - "(res)sgat=%d low_dma=%d\n", - k, fp->timeout, fp->reserve.bufflen, + for (k = 0; (fp = sg_get_nth_sfp(sdp, k)); ++k) { + PRINT_PROC(" FD(%d): timeout=%dms bufflen=%d " + "(res)sgat=%d low_dma=%d\n", k + 1, + sg_jif_to_ms(fp->timeout), fp->reserve.bufflen, (int)fp->reserve.k_use_sg, (int)fp->low_dma); PRINT_PROC(" cmd_q=%d f_packid=%d k_orphan=%d closed=%d\n", (int)fp->cmd_q, (int)fp->force_packid, (int)fp->keep_orphan, (int)fp->closed); - srp = fp->headrp; - if (NULL == srp) - PRINT_PROC(" No requests active\n"); - while (srp) { + for (m = 0; (srp = sg_get_nth_request(fp, m)); ++m) { hp = &srp->header; /* stop indenting so far ... */ PRINT_PROC(srp->res_used ? " rb>> " : ((SG_INFO_DIRECT_IO_MASK & hp->info) ? " dio>> " : " ")); blen = srp->my_cmdp ? srp->my_cmdp->bufflen : srp->data.bufflen; usg = srp->my_cmdp ? srp->my_cmdp->use_sg : srp->data.k_use_sg; - PRINT_PROC(srp->done ? "rcv: id=%d" : (srp->my_cmdp ? "act: id=%d" : - "prior: id=%d"), srp->header.pack_id); - PRINT_PROC(" blen=%d", blen); + PRINT_PROC(srp->done ? ((1 == srp->done) ? "rcv:" : "fin:") + : (srp->my_cmdp ? "act:" : "prior:")); + PRINT_PROC(" id=%d blen=%d", srp->header.pack_id, blen); if (srp->done) - PRINT_PROC(" dur=%d", sg_jif_to_ms(hp->duration)); + PRINT_PROC(" dur=%d", hp->duration); else PRINT_PROC(" t_o/elap=%d/%d", ((hp->interface_id == '\0') ? sg_jif_to_ms(fp->timeout) : hp->timeout), sg_jif_to_ms(hp->duration ? (jiffies - hp->duration) : 0)); - PRINT_PROC(" sgat=%d op=0x%02x\n", usg, (int)srp->data.cmd_opcode); - srp = srp->nextrp; + PRINT_PROC("ms sgat=%d op=0x%02x\n", usg, (int)srp->data.cmd_opcode); /* reset indenting */ } + if (0 == m) + PRINT_PROC(" No requests active\n"); } } } - read_unlock(&sg_dev_arr_lock); return 1; } @@ -2596,19 +2672,17 @@ static int sg_proc_dev_info(char * buffer, int * len, off_t * begin, int j, max_dev; struct scsi_device * scsidp; - read_lock(&sg_dev_arr_lock); max_dev = sg_last_dev(); for (j = 0; j < max_dev; ++j) { - sdp = sg_dev_arr[j]; + sdp = sg_get_dev(j); if (sdp && (scsidp = sdp->device)) PRINT_PROC("%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n", scsidp->host->host_no, scsidp->channel, scsidp->id, - scsidp->lun, (int)scsidp->type, (int)scsidp->disconnect, - (int)scsidp->queue_depth, (int)scsidp->tagged_queue); + scsidp->lun, (int)scsidp->type, (int)scsidp->access_count, + (int)scsidp->queue_depth, (int)scsidp->device_busy); else PRINT_PROC("-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\n"); } - read_unlock(&sg_dev_arr_lock); return 1; } @@ -2619,7 +2693,7 @@ static int sg_proc_devhdr_read(char * buffer, char ** start, off_t offset, static int sg_proc_devhdr_info(char * buffer, int * len, off_t * begin, off_t offset, int size) { - PRINT_PROC("host\tchan\tid\tlun\ttype\tdiscon\tqdepth\ttq\n"); + PRINT_PROC("host\tchan\tid\tlun\ttype\tbopens\tqdepth\tbusy\n"); return 1; } @@ -2634,17 +2708,15 @@ static int sg_proc_devstrs_info(char * buffer, int * len, off_t * begin, int j, max_dev; struct scsi_device * scsidp; - read_lock(&sg_dev_arr_lock); max_dev = sg_last_dev(); for (j = 0; j < max_dev; ++j) { - sdp = sg_dev_arr[j]; + sdp = sg_get_dev(j); if (sdp && (scsidp = sdp->device)) PRINT_PROC("%8.8s\t%16.16s\t%4.4s\n", scsidp->vendor, scsidp->model, scsidp->rev); else PRINT_PROC("<no active device>\n"); } - read_unlock(&sg_dev_arr_lock); return 1; } |