📄 sg.c
字号:
&sg_idp->d_queue_depth); __put_user(0, &sg_idp->unused[0]); __put_user(0, &sg_idp->unused[1]); return 0; } case SG_SET_FORCE_PACK_ID: result = get_user(val, (int *)arg); if (result) return result; sfp->force_packid = val ? 1 : 0; return 0; case SG_GET_PACK_ID: result = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int)); if (result) return result; 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; } } read_unlock_irqrestore(&sfp->rq_list_lock, iflags); __put_user(-1, (int *)arg); return 0; case SG_GET_NUM_WAITING: 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; } 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); case SG_SET_RESERVED_SIZE: result = get_user(val, (int *)arg); if (result) return result; if (val != sfp->reserve.bufflen) { if (sg_res_in_use(sfp)) return -EBUSY; sg_remove_scat(&sfp->reserve); sg_build_reserve(sfp, val); } return 0; case SG_GET_RESERVED_SIZE: val = (int)sfp->reserve.bufflen; return put_user(val, (int *)arg); case SG_SET_COMMAND_Q: result = get_user(val, (int *)arg); if (result) return result; sfp->cmd_q = val ? 1 : 0; return 0; case SG_GET_COMMAND_Q: return put_user((int)sfp->cmd_q, (int *)arg); case SG_SET_KEEP_ORPHAN: result = get_user(val, (int *)arg); if (result) return result; sfp->keep_orphan = val; return 0; case SG_GET_KEEP_ORPHAN: return put_user((int)sfp->keep_orphan, (int *)arg); case SG_NEXT_CMD_LEN: result = get_user(val, (int *)arg); if (result) return result; sfp->next_cmd_len = (val > 0) ? val : 0; return 0; case SG_GET_VERSION_NUM: return put_user(sg_version_num, (int *)arg); case SG_GET_REQUEST_TABLE: result = verify_area(VERIFY_WRITE, (void *) arg, size_sg_req_info * SG_MAX_QUEUE); if (result) return result; else { sg_req_info_t rinfo[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 + 1; rinfo[val].problem = srp->header.masked_status & srp->header.host_status & srp->header.driver_status; rinfo[val].duration = srp->done ? 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; rinfo[val].pack_id = srp->header.pack_id; 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; } case SG_EMULATED_HOST: return put_user(sdp->device->host->hostt->emulated, (int *)arg); case SG_SCSI_RESET: if (filp->f_flags & O_NONBLOCK) { if (sdp->device->host->in_recovery) return -EBUSY; } else if (! scsi_block_when_processing_errors(sdp->device)) return -EBUSY; result = get_user(val, (int *)arg); if (result) return result; 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; Scsi_Ioctl_Command * siocp = (void *)arg; copy_from_user(&opcode, siocp->data, 1); if (! sg_allow_access(opcode, sdp->device->type)) return -EACCES; } return scsi_ioctl_send_command(sdp->device, (void *)arg); case SG_SET_DEBUG: result = get_user(val, (int *)arg); if (result) return result; sdp->sgdebug = (char)val; return 0; case SCSI_IOCTL_GET_IDLUN: case SCSI_IOCTL_GET_BUS_NUMBER: case SCSI_IOCTL_PROBE_HOST: case SG_GET_TRANSFORM: return scsi_ioctl(sdp->device, cmd_in, (void *)arg); default: if (read_only) return -EACCES; /* don't know so take safe approach */ return scsi_ioctl(sdp->device, cmd_in, (void *)arg); }}static unsigned int sg_poll(struct file * filp, poll_table * wait){ unsigned int res = 0; Sg_device * sdp; 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); 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; } read_unlock_irqrestore(&sfp->rq_list_lock, iflags); if (! sfp->cmd_q) { if (0 == count) res |= POLLOUT | POLLWRNORM; } else if (count < SG_MAX_QUEUE) res |= POLLOUT | POLLWRNORM; SCSI_LOG_TIMEOUT(3, printk("sg_poll: dev=%d, res=0x%x\n", MINOR(sdp->i_rdev), (int)res)); return res;}static int sg_fasync(int fd, struct file * filp, int mode){ int retval; Sg_device * sdp; Sg_fd * sfp; if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) return -ENXIO; SCSI_LOG_TIMEOUT(3, printk("sg_fasync: dev=%d, mode=%d\n", MINOR(sdp->i_rdev), mode)); retval = fasync_helper(fd, filp, mode, &sfp->async_qp); return (retval < 0) ? retval : 0;}/* This function is a "bottom half" handler that is called by the * mid level when a command is completed (or has failed). */static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt){ Scsi_Request * SRpnt = SCpnt->sc_request; int dev = MINOR(SRpnt->sr_request.rq_dev); Sg_device * sdp = NULL; Sg_fd * sfp; Sg_request * srp = NULL; 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_request(SRpnt); SRpnt = NULL; return; } sfp = sdp->headfp; while (sfp) { read_lock(&sfp->rq_list_lock); for (srp = sfp->headrp; srp; srp = srp->nextrp) { if (SRpnt == srp->my_cmdp) break; } 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_request(SRpnt); SRpnt = NULL; return; } /* First transfer ownership of data buffers to sg_device object. */ srp->data.k_use_sg = SRpnt->sr_use_sg; srp->data.sglist_len = SRpnt->sr_sglist_len; srp->data.bufflen = SRpnt->sr_bufflen; srp->data.buffer = SRpnt->sr_buffer; sg_clr_srpnt(SRpnt); srp->my_cmdp = NULL; srp->done = 1; SCSI_LOG_TIMEOUT(4, printk("sg...bh: dev=%d, pack_id=%d, res=0x%x\n", dev, srp->header.pack_id, (int)SRpnt->sr_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 != SRpnt->sr_result) { memcpy(srp->sense_b, SRpnt->sr_sense_buffer, sizeof(srp->sense_b)); srp->header.status = 0xff & SRpnt->sr_result; srp->header.masked_status = status_byte(SRpnt->sr_result); srp->header.msg_status = msg_byte(SRpnt->sr_result); srp->header.host_status = host_byte(SRpnt->sr_result); srp->header.driver_status = driver_byte(SRpnt->sr_result); if ((sdp->sgdebug > 0) && ((CHECK_CONDITION == srp->header.masked_status) || (COMMAND_TERMINATED == srp->header.masked_status))) print_req_sense("sg_cmd_done_bh", SRpnt); /* Following if statement is a patch supplied by Eric Youngdale */ if (driver_byte(SRpnt->sr_result) != 0 && (SRpnt->sr_sense_buffer[0] & 0x7f) == 0x70 && (SRpnt->sr_sense_buffer[2] & 0xf) == UNIT_ATTENTION && sdp->device->removable) { /* Detected disc change. Set the bit - this may be used if */ /* there are filesystems using this device. */ sdp->device->changed = 1; } } /* Rely on write phase to clean out srp status values, so no "else" */ scsi_release_request(SRpnt); SRpnt = NULL; if (sfp->closed) { /* whoops this fd already released, cleanup */ SCSI_LOG_TIMEOUT(1, printk("sg...bh: already closed, freeing ...\n")); /* should check if module is unloaded <<<<<<< */ sg_finish_rem_req(srp); srp = NULL; if (NULL == sfp->headrp) { SCSI_LOG_TIMEOUT(1, printk("sg...bh: already closed, final cleanup\n")); sg_remove_sfp(sdp, sfp); sfp = NULL; } } else if (srp && srp->orphan) { if (sfp->keep_orphan) srp->sg_io_owned = 0; else { sg_finish_rem_req(srp); srp = NULL; } } if (sfp && srp) { /* Now wake up any sg_read() that is waiting for this packet. */ wake_up_interruptible(&sfp->read_wait); kill_fasync(&sfp->async_qp, SIGPOLL, POLL_IN); }}static struct file_operations sg_fops = { owner: THIS_MODULE, read: sg_read, write: sg_write, poll: sg_poll, ioctl: sg_ioctl, open: sg_open, release: sg_release, fasync: sg_fasync,};static int sg_detect(Scsi_Device * scsidp){ switch (scsidp->type) { case TYPE_DISK: case TYPE_MOD: case TYPE_ROM: case TYPE_WORM: case TYPE_TAPE: break; default: printk("Detected scsi generic sg%d at scsi%d," " channel %d, id %d, lun %d, type %d\n", sg_template.dev_noticed, scsidp->host->host_no, scsidp->channel, scsidp->id, scsidp->lun, scsidp->type); } sg_template.dev_noticed++; return 1;}/* Driver initialization */static int sg_init(){ static int sg_registered = 0; unsigned long iflags; if ((sg_template.dev_noticed == 0) || sg_dev_arr) return 0; 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, iflags); return 1; } sg_registered++; } SCSI_LOG_TIMEOUT(3, printk("sg_init\n")); sg_template.dev_max = sg_template.dev_noticed + SG_DEV_ARR_LUMP; sg_dev_arr = (Sg_device **)kmalloc(sg_template.dev_max * 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, iflags); return 1; } memset(sg_dev_arr, 0, sg_template.dev_max * sizeof(Sg_device *)); write_unlock_irqrestore(&sg_dev_arr_lock, iflags);#ifdef CONFIG_PROC_FS sg_proc_init();#endif /* CONFIG_PROC_FS */ return 0;}#ifndef MODULEstatic int __init sg_def_reserved_size_setup(char *str){ int tmp; if (get_option(&str, &tmp) == 1) { def_reserved_size = tmp; if (tmp >= 0) sg_big_buff = tmp; return 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -