Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 24c14200 authored by Lalit Chandivade's avatar Lalit Chandivade Committed by James Bottomley
Browse files

[SCSI] qla4xxx: Properly handle SCSI underrun while processing status IOCBs.



The current code would incorrectly return a DID_OK for a
CHECK CONDITION with Recovered error sense key causing incorrect
completion of a command when there is a dropped frame.

Signed-off-by: default avatarLalit Chandivade <lalit.chandivade@qlogic.com>
Signed-off-by: default avatarTej Parkash <tej.parkash@qlogic.com>
Signed-off-by: default avatarVikas Chaudhary <vikas.chaudhary@qlogic.com>
Reviewed-by: default avatarMike Christie <michaelc@cs.wisc.edu>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent 80c53e64
Loading
Loading
Loading
Loading
+59 −43
Original line number Diff line number Diff line
@@ -243,56 +243,72 @@ static void qla4xxx_status_entry(struct scsi_qla_host *ha,

		scsi_set_resid(cmd, residual);

		/*
		 * If there is scsi_status, it takes precedense over
		 * underflow condition.
		if (sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_UNDER) {

			/* Both the firmware and target reported UNDERRUN:
			 *
			 * MID-LAYER UNDERFLOW case:
			 * Some kernels do not properly detect midlayer
			 * underflow, so we manually check it and return
			 * ERROR if the minimum required data was not
			 * received.
			 *
			 * ALL OTHER cases:
			 * Fall thru to check scsi_status
			 */
		if (scsi_status != 0) {
			cmd->result = DID_OK << 16 | scsi_status;
			if (!scsi_status && (scsi_bufflen(cmd) - residual) <
			    cmd->underflow) {
				DEBUG2(ql4_printk(KERN_INFO, ha,
						  "scsi%ld:%d:%d:%d: %s: Mid-layer Data underrun, xferlen = 0x%x,residual = 0x%x\n",
						   ha->host_no,
						   cmd->device->channel,
						   cmd->device->id,
						   cmd->device->lun, __func__,
						   scsi_bufflen(cmd),
						   residual));

			if (scsi_status != SCSI_CHECK_CONDITION)
				cmd->result = DID_ERROR << 16;
				break;
			}

		} else if (scsi_status != SAM_STAT_TASK_SET_FULL &&
			   scsi_status != SAM_STAT_BUSY) {

			/* Copy Sense Data into sense buffer. */
			qla4xxx_copy_sense(ha, sts_entry, srb);
		} else {
			/*
			 * If RISC reports underrun and target does not
			 * report it then we must have a lost frame, so
			 * tell upper layer to retry it by reporting a
			 * bus busy.
			 */
			if ((sts_entry->iscsiFlags &
			     ISCSI_FLAG_RESIDUAL_UNDER) == 0) {
				cmd->result = DID_BUS_BUSY << 16;
			} else if ((scsi_bufflen(cmd) - residual) <
				   cmd->underflow) {
			/*
				 * Handle mid-layer underflow???
			 * The firmware reports UNDERRUN, but the target does
			 * not report it:
			 *
				 * For kernels less than 2.4, the driver must
				 * return an error if an underflow is detected.
				 * For kernels equal-to and above 2.4, the
				 * mid-layer will appearantly handle the
				 * underflow by detecting the residual count --
				 * unfortunately, we do not see where this is
				 * actually being done.	 In the interim, we
				 * will return DID_ERROR.
			 *   scsi_status     |    host_byte       device_byte
			 *                   |     (19:16)          (7:0)
			 *   =============   |    =========       ===========
			 *   TASK_SET_FULL   |    DID_OK          scsi_status
			 *   BUSY            |    DID_OK          scsi_status
			 *   ALL OTHERS      |    DID_ERROR       scsi_status
			 *
			 *   Note: If scsi_status is task set full or busy,
			 *   then this else if would fall thru to check the
			 *   scsi_status and return DID_OK.
			 */
				DEBUG2(printk("scsi%ld:%d:%d:%d: %s: "
					"Mid-layer Data underrun1, "
					"xferlen = 0x%x, "
					"residual = 0x%x\n", ha->host_no,

			DEBUG2(ql4_printk(KERN_INFO, ha,
					  "scsi%ld:%d:%d:%d: %s: Dropped frame(s) detected (0x%x of 0x%x bytes).\n",
					  ha->host_no,
					  cmd->device->channel,
					  cmd->device->id,
					  cmd->device->lun, __func__,
					scsi_bufflen(cmd), residual));
					  residual,
					  scsi_bufflen(cmd)));

				cmd->result = DID_ERROR << 16;
			} else {
				cmd->result = DID_OK << 16;
			}
			cmd->result = DID_ERROR << 16 | scsi_status;
			goto check_scsi_status;
		}

		cmd->result = DID_OK << 16 | scsi_status;

check_scsi_status:
		if (scsi_status == SAM_STAT_CHECK_CONDITION)
			qla4xxx_copy_sense(ha, sts_entry, srb);

		break;

	case SCS_DEVICE_LOGGED_OUT: