|
@@ -526,6 +526,8 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req)
|
|
|
return -EIO;
|
|
|
}
|
|
|
|
|
|
+ zfcp_scsi_set_prot(adapter);
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -988,6 +990,7 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
|
|
|
bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req, sg_req);
|
|
|
if (bytes <= 0)
|
|
|
return -EIO;
|
|
|
+ zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req);
|
|
|
req->qtcb->bottom.support.req_buf_length = bytes;
|
|
|
zfcp_qdio_skip_to_last_sbale(&req->qdio_req);
|
|
|
|
|
@@ -996,6 +999,7 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
|
|
|
req->qtcb->bottom.support.resp_buf_length = bytes;
|
|
|
if (bytes <= 0)
|
|
|
return -EIO;
|
|
|
+ zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -2038,9 +2042,13 @@ static void zfcp_fsf_req_trace(struct zfcp_fsf_req *req, struct scsi_cmnd *scsi)
|
|
|
blktrc.fabric_lat = lat_in->fabric_lat * ticks;
|
|
|
|
|
|
switch (req->qtcb->bottom.io.data_direction) {
|
|
|
+ case FSF_DATADIR_DIF_READ_STRIP:
|
|
|
+ case FSF_DATADIR_DIF_READ_CONVERT:
|
|
|
case FSF_DATADIR_READ:
|
|
|
lat = &unit->latencies.read;
|
|
|
break;
|
|
|
+ case FSF_DATADIR_DIF_WRITE_INSERT:
|
|
|
+ case FSF_DATADIR_DIF_WRITE_CONVERT:
|
|
|
case FSF_DATADIR_WRITE:
|
|
|
lat = &unit->latencies.write;
|
|
|
break;
|
|
@@ -2081,6 +2089,21 @@ static void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req)
|
|
|
goto skip_fsfstatus;
|
|
|
}
|
|
|
|
|
|
+ switch (req->qtcb->header.fsf_status) {
|
|
|
+ case FSF_INCONSISTENT_PROT_DATA:
|
|
|
+ case FSF_INVALID_PROT_PARM:
|
|
|
+ set_host_byte(scpnt, DID_ERROR);
|
|
|
+ goto skip_fsfstatus;
|
|
|
+ case FSF_BLOCK_GUARD_CHECK_FAILURE:
|
|
|
+ zfcp_scsi_dif_sense_error(scpnt, 0x1);
|
|
|
+ goto skip_fsfstatus;
|
|
|
+ case FSF_APP_TAG_CHECK_FAILURE:
|
|
|
+ zfcp_scsi_dif_sense_error(scpnt, 0x2);
|
|
|
+ goto skip_fsfstatus;
|
|
|
+ case FSF_REF_TAG_CHECK_FAILURE:
|
|
|
+ zfcp_scsi_dif_sense_error(scpnt, 0x3);
|
|
|
+ goto skip_fsfstatus;
|
|
|
+ }
|
|
|
fcp_rsp = (struct fcp_resp_with_ext *) &req->qtcb->bottom.io.fcp_rsp;
|
|
|
zfcp_fc_eval_fcp_rsp(fcp_rsp, scpnt);
|
|
|
|
|
@@ -2190,6 +2213,44 @@ skip_fsfstatus:
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static int zfcp_fsf_set_data_dir(struct scsi_cmnd *scsi_cmnd, u32 *data_dir)
|
|
|
+{
|
|
|
+ switch (scsi_get_prot_op(scsi_cmnd)) {
|
|
|
+ case SCSI_PROT_NORMAL:
|
|
|
+ switch (scsi_cmnd->sc_data_direction) {
|
|
|
+ case DMA_NONE:
|
|
|
+ *data_dir = FSF_DATADIR_CMND;
|
|
|
+ break;
|
|
|
+ case DMA_FROM_DEVICE:
|
|
|
+ *data_dir = FSF_DATADIR_READ;
|
|
|
+ break;
|
|
|
+ case DMA_TO_DEVICE:
|
|
|
+ *data_dir = FSF_DATADIR_WRITE;
|
|
|
+ break;
|
|
|
+ case DMA_BIDIRECTIONAL:
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case SCSI_PROT_READ_STRIP:
|
|
|
+ *data_dir = FSF_DATADIR_DIF_READ_STRIP;
|
|
|
+ break;
|
|
|
+ case SCSI_PROT_WRITE_INSERT:
|
|
|
+ *data_dir = FSF_DATADIR_DIF_WRITE_INSERT;
|
|
|
+ break;
|
|
|
+ case SCSI_PROT_READ_PASS:
|
|
|
+ *data_dir = FSF_DATADIR_DIF_READ_CONVERT;
|
|
|
+ break;
|
|
|
+ case SCSI_PROT_WRITE_PASS:
|
|
|
+ *data_dir = FSF_DATADIR_DIF_WRITE_CONVERT;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* zfcp_fsf_send_fcp_command_task - initiate an FCP command (for a SCSI command)
|
|
|
* @unit: unit where command is sent to
|
|
@@ -2201,9 +2262,10 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
|
|
|
struct zfcp_fsf_req *req;
|
|
|
struct fcp_cmnd *fcp_cmnd;
|
|
|
unsigned int sbtype = SBAL_FLAGS0_TYPE_READ;
|
|
|
- int real_bytes, retval = -EIO;
|
|
|
+ int real_bytes, retval = -EIO, dix_bytes = 0;
|
|
|
struct zfcp_adapter *adapter = unit->port->adapter;
|
|
|
struct zfcp_qdio *qdio = adapter->qdio;
|
|
|
+ struct fsf_qtcb_bottom_io *io;
|
|
|
|
|
|
if (unlikely(!(atomic_read(&unit->status) &
|
|
|
ZFCP_STATUS_COMMON_UNBLOCKED)))
|
|
@@ -2226,46 +2288,46 @@ int zfcp_fsf_send_fcp_command_task(struct zfcp_unit *unit,
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
+ scsi_cmnd->host_scribble = (unsigned char *) req->req_id;
|
|
|
+
|
|
|
+ io = &req->qtcb->bottom.io;
|
|
|
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
|
|
|
req->unit = unit;
|
|
|
req->data = scsi_cmnd;
|
|
|
req->handler = zfcp_fsf_send_fcp_command_handler;
|
|
|
req->qtcb->header.lun_handle = unit->handle;
|
|
|
req->qtcb->header.port_handle = unit->port->handle;
|
|
|
- req->qtcb->bottom.io.service_class = FSF_CLASS_3;
|
|
|
- req->qtcb->bottom.io.fcp_cmnd_length = FCP_CMND_LEN;
|
|
|
+ io->service_class = FSF_CLASS_3;
|
|
|
+ io->fcp_cmnd_length = FCP_CMND_LEN;
|
|
|
|
|
|
- scsi_cmnd->host_scribble = (unsigned char *) req->req_id;
|
|
|
-
|
|
|
- /*
|
|
|
- * set depending on data direction:
|
|
|
- * data direction bits in SBALE (SB Type)
|
|
|
- * data direction bits in QTCB
|
|
|
- */
|
|
|
- switch (scsi_cmnd->sc_data_direction) {
|
|
|
- case DMA_NONE:
|
|
|
- req->qtcb->bottom.io.data_direction = FSF_DATADIR_CMND;
|
|
|
- break;
|
|
|
- case DMA_FROM_DEVICE:
|
|
|
- req->qtcb->bottom.io.data_direction = FSF_DATADIR_READ;
|
|
|
- break;
|
|
|
- case DMA_TO_DEVICE:
|
|
|
- req->qtcb->bottom.io.data_direction = FSF_DATADIR_WRITE;
|
|
|
- break;
|
|
|
- case DMA_BIDIRECTIONAL:
|
|
|
- goto failed_scsi_cmnd;
|
|
|
+ if (scsi_get_prot_op(scsi_cmnd) != SCSI_PROT_NORMAL) {
|
|
|
+ io->data_block_length = scsi_cmnd->device->sector_size;
|
|
|
+ io->ref_tag_value = scsi_get_lba(scsi_cmnd) & 0xFFFFFFFF;
|
|
|
}
|
|
|
|
|
|
+ zfcp_fsf_set_data_dir(scsi_cmnd, &io->data_direction);
|
|
|
+
|
|
|
get_device(&unit->dev);
|
|
|
|
|
|
fcp_cmnd = (struct fcp_cmnd *) &req->qtcb->bottom.io.fcp_cmnd;
|
|
|
zfcp_fc_scsi_to_fcp(fcp_cmnd, scsi_cmnd);
|
|
|
|
|
|
+ if (scsi_prot_sg_count(scsi_cmnd)) {
|
|
|
+ zfcp_qdio_set_data_div(qdio, &req->qdio_req,
|
|
|
+ scsi_prot_sg_count(scsi_cmnd));
|
|
|
+ dix_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
|
|
|
+ scsi_prot_sglist(scsi_cmnd));
|
|
|
+ io->prot_data_length = dix_bytes;
|
|
|
+ }
|
|
|
+
|
|
|
real_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
|
|
|
scsi_sglist(scsi_cmnd));
|
|
|
- if (unlikely(real_bytes < 0))
|
|
|
+
|
|
|
+ if (unlikely(real_bytes < 0) || unlikely(dix_bytes < 0))
|
|
|
goto failed_scsi_cmnd;
|
|
|
|
|
|
+ zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req);
|
|
|
+
|
|
|
retval = zfcp_fsf_req_send(req);
|
|
|
if (unlikely(retval))
|
|
|
goto failed_scsi_cmnd;
|
|
@@ -2389,6 +2451,7 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
|
|
|
zfcp_fsf_req_free(req);
|
|
|
goto out;
|
|
|
}
|
|
|
+ zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req);
|
|
|
|
|
|
zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
|
|
|
retval = zfcp_fsf_req_send(req);
|