Hi all, Today's linux-next merge of the scsi-mkp tree got a conflict in: drivers/scsi/sg.c between commit: 8eeed0b554b9 ("block: remove unnecessary argument from blk_execute_rq_nowait") from the block tree and vaious commits from the scsi-mkp tree. I fixed it up (see below) and can carry the fix as necessary. This is now fixed as far as linux-next is concerned, but any non trivial conflicts should be mentioned to your upstream maintainer when your tree is submitted for merging. You may also want to consider cooperating with the maintainer of the conflicting tree to minimise any particularly complex conflicts. -- Cheers, Stephen Rothwell diff --cc drivers/scsi/sg.c index 4383d93110f8,c5a34bb91335..000000000000 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@@ -437,73 -858,243 +858,242 @@@ sg_rq_state_chg(struct sg_request *srp return 0; } - static ssize_t - sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) + /* + * All writes and submits converge on this function to launch the SCSI + * command/request (via blk_execute_rq_nowait). Returns a pointer to a + * sg_request object holding the request just issued or a negated errno + * value twisted by ERR_PTR. + */ + static struct sg_request * + sg_common_write(struct sg_fd *sfp, struct sg_comm_wr_t *cwrp) { - Sg_device *sdp; - Sg_fd *sfp; - Sg_request *srp; - int req_pack_id = -1; - sg_io_hdr_t *hp; - struct sg_header *old_hdr; - int retval; + bool at_head; + int res = 0; + int dxfr_len, dir, cmd_len; + int pack_id = SG_PACK_ID_WILDCARD; + u32 rq_flags; + struct sg_device *sdp = sfp->parentdp; + struct sg_request *srp; + struct sg_io_hdr *hi_p; + + hi_p = cwrp->h3p; + dir = hi_p->dxfer_direction; + dxfr_len = hi_p->dxfer_len; + rq_flags = hi_p->flags; + pack_id = hi_p->pack_id; + if (dxfr_len >= SZ_256M) + return ERR_PTR(-EINVAL); + + srp = sg_setup_req(sfp, dxfr_len, cwrp); + if (IS_ERR(srp)) + return srp; + srp->rq_flags = rq_flags; + srp->pack_id = pack_id; + + cmd_len = hi_p->cmd_len; + memcpy(&srp->s_hdr3, hi_p, sizeof(srp->s_hdr3)); + srp->cmd_opcode = cwrp->cmnd[0];/* hold opcode of command for debug */ + SG_LOG(4, sfp, "%s: opcode=0x%02x, cdb_sz=%d, pack_id=%d\n", __func__, + (int)cwrp->cmnd[0], cmd_len, pack_id); + + res = sg_start_req(srp, cwrp->cmnd, cmd_len, dir); + if (res < 0) /* probably out of space --> -ENOMEM */ + goto err_out; + if (unlikely(SG_IS_DETACHING(sdp))) { + res = -ENODEV; + goto err_out; + } + if (unlikely(test_bit(SG_FRQ_BLK_PUT_REQ, srp->frq_bm) || !srp->rq)) { + res = -EIDRM; /* this failure unexpected but observed */ + goto err_out; + } + if (xa_get_mark(&sfp->srp_arr, srp->rq_idx, SG_XA_RQ_FREE)) { + SG_LOG(1, sfp, "%s: ahhh, request erased!!!\n", __func__); + res = -ENODEV; + goto err_out; + } + srp->rq->timeout = cwrp->timeout; + kref_get(&sfp->f_ref); /* sg_rq_end_io() does kref_put(). */ + res = sg_rq_state_chg(srp, SG_RS_BUSY, SG_RS_INFLIGHT, false, + __func__); + if (res) + goto err_out; + srp->start_ns = ktime_get_boottime_ns(); + srp->duration = 0; + + if (srp->s_hdr3.interface_id == '\0') + at_head = true; /* backward compatibility: v1+v2 interfaces */ + else if (test_bit(SG_FFD_Q_AT_TAIL, sfp->ffd_bm)) + /* cmd flags can override sfd setting */ + at_head = !!(srp->rq_flags & SG_FLAG_Q_AT_HEAD); + else /* this sfd is defaulting to head */ + at_head = !(srp->rq_flags & SG_FLAG_Q_AT_TAIL); + if (!test_bit(SG_FRQ_SYNC_INVOC, srp->frq_bm)) + atomic_inc(&sfp->submitted); - blk_execute_rq_nowait(sdp->device->request_queue, sdp->disk, - srp->rq, at_head, sg_rq_end_io); ++ blk_execute_rq_nowait(sdp->disk, srp->rq, at_head, sg_rq_end_io); + return srp; + err_out: + sg_finish_scsi_blk_rq(srp); + sg_deact_request(sfp, srp); + return ERR_PTR(res); + } - /* - * This could cause a response to be stranded. Close the associated - * file descriptor to free up any resources being held. - */ - retval = sg_check_file_access(filp, __func__); - if (retval) - return retval; + /* + * This function is called by wait_event_interruptible in sg_read() and + * sg_ctl_ioreceive(). wait_event_interruptible will return if this one + * returns true (or an event like a signal (e.g. control-C) occurs). + */ - if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) - return -ENXIO; - SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp, - "sg_read: count=%d\n", (int) count)); + static inline bool + sg_get_ready_srp(struct sg_fd *sfp, struct sg_request **srpp, int pack_id) + { + struct sg_request *srp; - if (sfp->force_packid) - retval = get_sg_io_pack_id(&req_pack_id, buf, count); - if (retval) - return retval; + if (unlikely(SG_IS_DETACHING(sfp->parentdp))) { + *srpp = NULL; + return true; + } + srp = sg_find_srp_by_id(sfp, pack_id); + *srpp = srp; + return !!srp; + } - srp = sg_get_rq_mark(sfp, req_pack_id); - if (!srp) { /* now wait on packet to arrive */ - if (atomic_read(&sdp->detaching)) - return -ENODEV; - if (filp->f_flags & O_NONBLOCK) - return -EAGAIN; - retval = wait_event_interruptible(sfp->read_wait, - (atomic_read(&sdp->detaching) || - (srp = sg_get_rq_mark(sfp, req_pack_id)))); - if (atomic_read(&sdp->detaching)) - return -ENODEV; - if (retval) - /* -ERESTARTSYS as signal hit process */ - return retval; + /* + * Returns number of bytes copied to user space provided sense buffer or + * negated errno value. + */ + static int + sg_copy_sense(struct sg_request *srp) + { + int sb_len_ret = 0; + int scsi_stat; + + /* If need be, copy the sense buffer to the user space */ + scsi_stat = srp->rq_result & 0xff; + if ((scsi_stat & SAM_STAT_CHECK_CONDITION) || + (driver_byte(srp->rq_result) & DRIVER_SENSE)) { + int sb_len = min_t(int, SCSI_SENSE_BUFFERSIZE, srp->sense_len); + int mx_sb_len = srp->s_hdr3.mx_sb_len; + u8 *sbp = srp->sense_bp; + void __user *up = srp->s_hdr3.sbp; + + srp->sense_bp = NULL; + if (up && mx_sb_len > 0 && sbp) { + sb_len = min_t(int, mx_sb_len, sb_len); + /* Additional sense length field */ + sb_len_ret = 8 + (int)sbp[7]; + sb_len_ret = min_t(int, sb_len_ret, sb_len); + if (copy_to_user(up, sbp, sb_len_ret)) + sb_len_ret = -EFAULT; + } else { + sb_len_ret = 0; + } + mempool_free(sbp, sg_sense_pool); } - if (srp->header.interface_id != '\0') - return sg_new_read(sfp, buf, count, srp); + return sb_len_ret; + } - hp = &srp->header; - old_hdr = kzalloc(SZ_SG_HEADER, GFP_KERNEL); - if (!old_hdr) - return -ENOMEM; + static int + sg_rec_state_v3(struct sg_fd *sfp, struct sg_request *srp) + { + int sb_len_wr; + u32 rq_res = srp->rq_result; + + sb_len_wr = sg_copy_sense(srp); + if (sb_len_wr < 0) + return sb_len_wr; + if (rq_res & SG_ML_RESULT_MSK) + srp->rq_info |= SG_INFO_CHECK; + if (unlikely(SG_IS_DETACHING(sfp->parentdp))) + srp->rq_info |= SG_INFO_DEVICE_DETACHING; + return 0; + } + + static ssize_t + sg_receive_v3(struct sg_fd *sfp, struct sg_request *srp, size_t count, + void __user *p) + { + int err, err2; + int rq_result = srp->rq_result; + struct sg_io_hdr hdr3; + struct sg_io_hdr *hp = &hdr3; - old_hdr->reply_len = (int) hp->timeout; - old_hdr->pack_len = old_hdr->reply_len; /* old, strange behaviour */ - 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 */ + if (in_compat_syscall()) { + if (count < sizeof(struct compat_sg_io_hdr)) { + err = -EINVAL; + goto err_out; + } + } else if (count < SZ_SG_IO_HDR) { + err = -EINVAL; + goto err_out; + } + SG_LOG(3, sfp, "%s: srp=0x%pK\n", __func__, srp); + err = sg_rec_state_v3(sfp, srp); + memset(hp, 0, sizeof(*hp)); + memcpy(hp, &srp->s_hdr3, sizeof(srp->s_hdr3)); + hp->sb_len_wr = srp->sense_len; + hp->info = srp->rq_info; + hp->resid = srp->in_resid; + hp->duration = srp->duration; + hp->status = rq_result & 0xff; + hp->masked_status = status_byte(rq_result); + hp->msg_status = msg_byte(rq_result); + hp->host_status = host_byte(rq_result); + hp->driver_status = driver_byte(rq_result); + err2 = put_sg_io_hdr(hp, p); + err = err ? err : err2; + err2 = sg_rq_state_chg(srp, atomic_read(&srp->rq_st), SG_RS_RCV_DONE, + false, __func__); + if (err2) + err = err ? err : err2; + err_out: + sg_finish_scsi_blk_rq(srp); + sg_deact_request(sfp, srp); + return err; + } + + /* + * Completes a v3 request/command. Called from sg_read {v2 or v3}, + * ioctl(SG_IO) {for v3}, or from ioctl(SG_IORECEIVE) when its + * completing a v3 request/command. + */ + static int + sg_read_v1v2(void __user *buf, int count, struct sg_fd *sfp, + struct sg_request *srp) + { + int res = 0; + u32 rq_result = srp->rq_result; + struct sg_header *h2p; + struct sg_slice_hdr3 *sh3p; + struct sg_header a_v2hdr; + + h2p = &a_v2hdr; + memset(h2p, 0, SZ_SG_HEADER); + sh3p = &srp->s_hdr3; + h2p->reply_len = (int)sh3p->timeout; + h2p->pack_len = h2p->reply_len; /* old, strange behaviour */ + h2p->pack_id = sh3p->pack_id; + h2p->twelve_byte = (srp->cmd_opcode >= 0xc0 && sh3p->cmd_len == 12); + h2p->target_status = status_byte(rq_result); + h2p->host_status = host_byte(rq_result); + h2p->driver_status = driver_byte(rq_result); + if ((CHECK_CONDITION & status_byte(rq_result)) || + (DRIVER_SENSE & driver_byte(rq_result))) { + if (srp->sense_bp) { + u8 *sbp = srp->sense_bp; + + srp->sense_bp = NULL; + memcpy(h2p->sense_buffer, sbp, + sizeof(h2p->sense_buffer)); + mempool_free(sbp, sg_sense_pool); + } + } + switch (host_byte(rq_result)) { + /* + * This following setting of 'result' is for backward compatibility + * and is best ignored by the user who should use target, host and + * driver status. + */ case DID_OK: case DID_PASSTHROUGH: case DID_SOFT_ERROR:
Attachment:
pgpg5shMXRzV3.pgp
Description: OpenPGP digital signature