📄 sg.c
字号:
old_hdr.pack_id = hp->pack_id; old_hdr.twelve_byte = ((srp->data.cmd_opcode >= 0xc0) && (12 == hp->cmd_len)) ? 1 : 0; old_hdr.target_status = hp->masked_status; old_hdr.host_status = hp->host_status; old_hdr.driver_status = hp->driver_status; if ((CHECK_CONDITION & hp->masked_status) || (DRIVER_SENSE & hp->driver_status)) memcpy(old_hdr.sense_buffer, srp->sense_b, sizeof(old_hdr.sense_buffer)); switch (hp->host_status) { /* This setup of 'result' is for backward compatibility and is best ignored by the user who should use target, host + driver status */ case DID_OK: case DID_PASSTHROUGH: case DID_SOFT_ERROR: old_hdr.result = 0; break; case DID_NO_CONNECT: case DID_BUS_BUSY: case DID_TIME_OUT: old_hdr.result = EBUSY; break; case DID_BAD_TARGET: case DID_ABORT: case DID_PARITY: case DID_RESET: case DID_BAD_INTR: old_hdr.result = EIO; break; case DID_ERROR: old_hdr.result = (srp->sense_b[0] == 0 && hp->masked_status == GOOD) ? 0 : EIO; break; default: old_hdr.result = EIO; break; } /* Now copy the result back to the user buffer. */ if (count >= size_sg_header) { __copy_to_user(buf, &old_hdr, size_sg_header); buf += size_sg_header; if (count > old_hdr.reply_len) count = old_hdr.reply_len; if (count > size_sg_header) sg_read_oxfer(srp, buf, count - size_sg_header); } else count = (old_hdr.result == 0) ? 0 : -EIO; sg_finish_rem_req(srp); return count;}static ssize_t sg_new_read(Sg_fd * sfp, char * buf, size_t count, Sg_request * srp){ sg_io_hdr_t * hp = &srp->header; int k, len; if (count < size_sg_io_hdr) return -EINVAL; hp->sb_len_wr = 0; if ((hp->mx_sb_len > 0) && hp->sbp) { if ((CHECK_CONDITION & hp->masked_status) || (DRIVER_SENSE & hp->driver_status)) { int sb_len = sizeof(dummy_cmdp->sr_sense_buffer); sb_len = (hp->mx_sb_len > sb_len) ? sb_len : hp->mx_sb_len; len = 8 + (int)srp->sense_b[7]; /* Additional sense length field */ len = (len > sb_len) ? sb_len : len; if ((k = verify_area(VERIFY_WRITE, hp->sbp, len))) return k; __copy_to_user(hp->sbp, srp->sense_b, len); hp->sb_len_wr = len; } } if (hp->masked_status || hp->host_status || hp->driver_status) hp->info |= SG_INFO_CHECK; copy_to_user(buf, hp, size_sg_io_hdr); k = sg_read_xfer(srp); if (k) return k; /* probably -EFAULT, bad addr in dxferp or iovec list */ sg_finish_rem_req(srp); return count;}static ssize_t sg_write(struct file * filp, const char * buf, size_t count, loff_t *ppos){ int mxsize, cmd_size, k; int input_size, blocking; unsigned char opcode; Sg_device * sdp; Sg_fd * sfp; Sg_request * srp; struct sg_header old_hdr; sg_io_hdr_t * hp; unsigned char cmnd[sizeof(dummy_cmdp->sr_cmnd)]; if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) return -ENXIO; SCSI_LOG_TIMEOUT(3, printk("sg_write: dev=%d, count=%d\n", MINOR(sdp->i_rdev), (int)count)); if (! ((filp->f_flags & O_NONBLOCK) || scsi_block_when_processing_errors(sdp->device))) return -ENXIO; if (ppos != &filp->f_pos) ; /* FIXME: Hmm. Seek to the right place, or fail? */ if ((k = verify_area(VERIFY_READ, buf, count))) return k; /* protects following copy_from_user()s + get_user()s */ if (count < size_sg_header) return -EIO; __copy_from_user(&old_hdr, buf, size_sg_header); blocking = !(filp->f_flags & O_NONBLOCK); if (old_hdr.reply_len < 0) return sg_new_write(sfp, buf, count, blocking, 0, NULL); if (count < (size_sg_header + 6)) return -EIO; /* The minimum scsi command length is 6 bytes. */ if (! (srp = sg_add_request(sfp))) { SCSI_LOG_TIMEOUT(1, printk("sg_write: queue full\n")); return -EDOM; } buf += size_sg_header; __get_user(opcode, buf); if (sfp->next_cmd_len > 0) { if (sfp->next_cmd_len > MAX_COMMAND_SIZE) { SCSI_LOG_TIMEOUT(1, printk("sg_write: command length too long\n")); sfp->next_cmd_len = 0; sg_remove_request(sfp, srp); return -EIO; } cmd_size = sfp->next_cmd_len; sfp->next_cmd_len = 0; /* reset so only this write() effected */ } else { cmd_size = COMMAND_SIZE(opcode); /* based on SCSI command group */ if ((opcode >= 0xc0) && old_hdr.twelve_byte) cmd_size = 12; } SCSI_LOG_TIMEOUT(4, printk("sg_write: scsi opcode=0x%02x, cmd_size=%d\n", (int)opcode, cmd_size));/* Determine buffer size. */ input_size = count - cmd_size; mxsize = (input_size > old_hdr.reply_len) ? input_size : old_hdr.reply_len; mxsize -= size_sg_header; input_size -= size_sg_header; if (input_size < 0) { sg_remove_request(sfp, srp); return -EIO; /* User did not pass enough bytes for this command. */ } hp = &srp->header; hp->interface_id = '\0'; /* indicator of old interface tunnelled */ hp->cmd_len = (unsigned char)cmd_size; hp->iovec_count = 0; hp->mx_sb_len = 0;#if 0 hp->dxfer_direction = SG_DXFER_UNKNOWN;#else if (input_size > 0) hp->dxfer_direction = ((old_hdr.reply_len - size_sg_header) > 0) ? SG_DXFER_TO_FROM_DEV : SG_DXFER_TO_DEV; else hp->dxfer_direction = (mxsize > 0) ? SG_DXFER_FROM_DEV : SG_DXFER_NONE;#endif hp->dxfer_len = mxsize; hp->dxferp = (unsigned char *)buf + cmd_size; hp->sbp = NULL; hp->timeout = old_hdr.reply_len; /* structure abuse ... */ hp->flags = input_size; /* structure abuse ... */ hp->pack_id = old_hdr.pack_id; hp->usr_ptr = NULL; __copy_from_user(cmnd, buf, cmd_size); k = sg_common_write(sfp, srp, cmnd, sfp->timeout, blocking); return (k < 0) ? k : count;}static ssize_t sg_new_write(Sg_fd * sfp, const char * buf, size_t count, int blocking, int read_only, Sg_request ** o_srp){ int k; Sg_request * srp; sg_io_hdr_t * hp; unsigned char cmnd[sizeof(dummy_cmdp->sr_cmnd)]; int timeout; if (count < size_sg_io_hdr) return -EINVAL; if ((k = verify_area(VERIFY_READ, buf, count))) return k; /* protects following copy_from_user()s + get_user()s */ sfp->cmd_q = 1; /* when sg_io_hdr seen, set command queuing on */ if (! (srp = sg_add_request(sfp))) { SCSI_LOG_TIMEOUT(1, printk("sg_new_write: queue full\n")); return -EDOM; } hp = &srp->header; __copy_from_user(hp, buf, size_sg_io_hdr); if (hp->interface_id != 'S') { sg_remove_request(sfp, srp); return -ENOSYS; } timeout = sg_ms_to_jif(srp->header.timeout); if ((! hp->cmdp) || (hp->cmd_len < 6) || (hp->cmd_len > sizeof(cmnd))) { sg_remove_request(sfp, srp); return -EMSGSIZE; } if ((k = verify_area(VERIFY_READ, hp->cmdp, hp->cmd_len))) { sg_remove_request(sfp, srp); return k; /* protects following copy_from_user()s + get_user()s */ } __copy_from_user(cmnd, hp->cmdp, hp->cmd_len); if (read_only && (! sg_allow_access(cmnd[0], sfp->parentdp->device->type))) { sg_remove_request(sfp, srp); return -EACCES; } k = sg_common_write(sfp, srp, cmnd, timeout, blocking); if (k < 0) return k; if (o_srp) *o_srp = srp; return count;}static int sg_common_write(Sg_fd * sfp, Sg_request * srp, unsigned char * cmnd, int timeout, int blocking){ int k; Scsi_Request * SRpnt; Sg_device * sdp = sfp->parentdp; sg_io_hdr_t * hp = &srp->header; srp->data.cmd_opcode = cmnd[0]; /* hold opcode of command */ hp->status = 0; hp->masked_status = 0; hp->msg_status = 0; hp->info = 0; hp->host_status = 0; hp->driver_status = 0; hp->resid = 0; SCSI_LOG_TIMEOUT(4, printk("sg_common_write: scsi opcode=0x%02x, cmd_size=%d\n", (int)cmnd[0], (int)hp->cmd_len)); if ((k = sg_start_req(srp))) { SCSI_LOG_TIMEOUT(1, printk("sg_write: start_req err=%d\n", k)); sg_finish_rem_req(srp); return k; /* probably out of space --> ENOMEM */ } if ((k = sg_write_xfer(srp))) { SCSI_LOG_TIMEOUT(1, printk("sg_write: write_xfer, bad address\n")); sg_finish_rem_req(srp); return k; }/* SCSI_LOG_TIMEOUT(7, printk("sg_write: allocating device\n")); */ SRpnt = scsi_allocate_request(sdp->device); if(SRpnt == NULL) { SCSI_LOG_TIMEOUT(1, printk("sg_write: no mem\n")); sg_finish_rem_req(srp); return -ENOMEM; }/* SCSI_LOG_TIMEOUT(7, printk("sg_write: device allocated\n")); */ srp->my_cmdp = SRpnt; SRpnt->sr_request.rq_dev = sdp->i_rdev; SRpnt->sr_request.rq_status = RQ_ACTIVE; SRpnt->sr_sense_buffer[0] = 0; SRpnt->sr_cmd_len = hp->cmd_len;/* Set the LUN field in the command structure, overriding user input */ if (! (hp->flags & SG_FLAG_LUN_INHIBIT)) cmnd[1] = (cmnd[1] & 0x1f) | (sdp->device->lun << 5);/* SCSI_LOG_TIMEOUT(7, printk("sg_write: do cmd\n")); */ SRpnt->sr_use_sg = srp->data.k_use_sg; SRpnt->sr_sglist_len = srp->data.sglist_len; SRpnt->sr_bufflen = srp->data.bufflen; SRpnt->sr_underflow = 0; SRpnt->sr_buffer = srp->data.buffer; switch (hp->dxfer_direction) { case SG_DXFER_TO_FROM_DEV: case SG_DXFER_FROM_DEV: SRpnt->sr_data_direction = SCSI_DATA_READ; break; case SG_DXFER_TO_DEV: SRpnt->sr_data_direction = SCSI_DATA_WRITE; break; case SG_DXFER_UNKNOWN: SRpnt->sr_data_direction = SCSI_DATA_UNKNOWN; break; default: SRpnt->sr_data_direction = SCSI_DATA_NONE; break; } srp->data.k_use_sg = 0; srp->data.sglist_len = 0; srp->data.bufflen = 0; srp->data.buffer = NULL; 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_req(SRpnt, (void *)cmnd, (void *)SRpnt->sr_buffer, hp->dxfer_len, sg_cmd_done_bh, timeout, SG_DEFAULT_RETRIES); /* dxfer_len overwrites SRpnt->sr_bufflen, hence need for b_malloc_len */ return 0;}static int sg_ioctl(struct inode * inode, struct file * filp, unsigned int cmd_in, unsigned long arg){ int result, val, read_only; Sg_device * sdp; Sg_fd * sfp; Sg_request * srp; unsigned long iflags; if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) return -ENXIO; SCSI_LOG_TIMEOUT(3, printk("sg_ioctl: dev=%d, cmd=0x%x\n", MINOR(sdp->i_rdev), (int)cmd_in)); read_only = (O_RDWR != (filp->f_flags & O_ACCMODE)); switch(cmd_in) { case SG_IO: { int blocking = 1; /* ignore O_NONBLOCK flag */ if(! scsi_block_when_processing_errors(sdp->device) ) return -ENXIO; result = verify_area(VERIFY_WRITE, (void *)arg, size_sg_io_hdr); if (result) return result; result = sg_new_write(sfp, (const char *)arg, size_sg_io_hdr, blocking, read_only, &srp); if (result < 0) return result; srp->sg_io_owned = 1; while (1) { int dio = sg_dio_in_use(sfp); result = 0; /* following macro to beat race condition */ __wait_event_interruptible(sfp->read_wait, (sfp->closed || srp->done), result); if (sfp->closed) return 0; /* request packet dropped already */ if (0 == result) break; else if (! dio) { /* only let signal out if no dio */ srp->orphan = 1; 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; } case SG_SET_TIMEOUT: result = get_user(val, (int *)arg); if (result) return result; if (val < 0) return -EIO; sfp->timeout = val; return 0; case SG_GET_TIMEOUT: /* N.B. User receives timeout as return value */ return sfp->timeout; /* strange ..., for backward compatibility */ case SG_SET_FORCE_LOW_DMA: result = get_user(val, (int *)arg); if (result) return result; if (val) { sfp->low_dma = 1; if ((0 == sfp->low_dma) && (0 == sg_res_in_use(sfp))) { val = (int)sfp->reserve.bufflen; sg_remove_scat(&sfp->reserve); sg_build_reserve(sfp, val); } } else sfp->low_dma = sdp->device->host->unchecked_isa_dma; return 0; case SG_GET_LOW_DMA: return put_user((int)sfp->low_dma, (int *)arg); case SG_GET_SCSI_ID: result = verify_area(VERIFY_WRITE, (void *)arg, sizeof(sg_scsi_id_t)); if (result) return result; else { sg_scsi_id_t * sg_idp = (sg_scsi_id_t *)arg; __put_user((int)sdp->device->host->host_no, &sg_idp->host_no); __put_user((int)sdp->device->channel, &sg_idp->channel); __put_user((int)sdp->device->id, &sg_idp->scsi_id); __put_user((int)sdp->device->lun, &sg_idp->lun); __put_user((int)sdp->device->type, &sg_idp->scsi_type); __put_user((short)sdp->device->host->cmd_per_lun, &sg_idp->h_cmd_per_lun); __put_user((short)sdp->device->queue_depth,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -