⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sg.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
    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 + -