[SCSI] zfcp: support for hardware data router
FICON Express8S supports hardware data router, which requires an adapted qdio request format. This part 2/2 exploits the functionality in zfcp. Signed-off-by: Swen Schillig <swen@vnet.ibm.com> Signed-off-by: Steffen Maier <maier@linux.vnet.ibm.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:
parent
dfe5bb5061
commit
86a9668a8d
@ -163,6 +163,42 @@ void zfcp_dbf_hba_bit_err(char *tag, struct zfcp_fsf_req *req)
|
|||||||
spin_unlock_irqrestore(&dbf->hba_lock, flags);
|
spin_unlock_irqrestore(&dbf->hba_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zfcp_dbf_hba_def_err - trace event for deferred error messages
|
||||||
|
* @adapter: pointer to struct zfcp_adapter
|
||||||
|
* @req_id: request id which caused the deferred error message
|
||||||
|
* @scount: number of sbals incl. the signaling sbal
|
||||||
|
* @pl: array of all involved sbals
|
||||||
|
*/
|
||||||
|
void zfcp_dbf_hba_def_err(struct zfcp_adapter *adapter, u64 req_id, u16 scount,
|
||||||
|
void **pl)
|
||||||
|
{
|
||||||
|
struct zfcp_dbf *dbf = adapter->dbf;
|
||||||
|
struct zfcp_dbf_pay *payload = &dbf->pay_buf;
|
||||||
|
unsigned long flags;
|
||||||
|
u16 length;
|
||||||
|
|
||||||
|
if (!pl)
|
||||||
|
return;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&dbf->pay_lock, flags);
|
||||||
|
memset(payload, 0, sizeof(*payload));
|
||||||
|
|
||||||
|
memcpy(payload->area, "def_err", 7);
|
||||||
|
payload->fsf_req_id = req_id;
|
||||||
|
payload->counter = 0;
|
||||||
|
length = min((u16)sizeof(struct qdio_buffer),
|
||||||
|
(u16)ZFCP_DBF_PAY_MAX_REC);
|
||||||
|
|
||||||
|
while ((char *)pl[payload->counter] && payload->counter < scount) {
|
||||||
|
memcpy(payload->data, (char *)pl[payload->counter], length);
|
||||||
|
debug_event(dbf->pay, 1, payload, zfcp_dbf_plen(length));
|
||||||
|
payload->counter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&dbf->pay_lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
static void zfcp_dbf_set_common(struct zfcp_dbf_rec *rec,
|
static void zfcp_dbf_set_common(struct zfcp_dbf_rec *rec,
|
||||||
struct zfcp_adapter *adapter,
|
struct zfcp_adapter *adapter,
|
||||||
struct zfcp_port *port,
|
struct zfcp_port *port,
|
||||||
|
@ -72,6 +72,7 @@ struct zfcp_reqlist;
|
|||||||
#define ZFCP_STATUS_COMMON_NOESC 0x00200000
|
#define ZFCP_STATUS_COMMON_NOESC 0x00200000
|
||||||
|
|
||||||
/* adapter status */
|
/* adapter status */
|
||||||
|
#define ZFCP_STATUS_ADAPTER_MB_ACT 0x00000001
|
||||||
#define ZFCP_STATUS_ADAPTER_QDIOUP 0x00000002
|
#define ZFCP_STATUS_ADAPTER_QDIOUP 0x00000002
|
||||||
#define ZFCP_STATUS_ADAPTER_SIOSL_ISSUED 0x00000004
|
#define ZFCP_STATUS_ADAPTER_SIOSL_ISSUED 0x00000004
|
||||||
#define ZFCP_STATUS_ADAPTER_XCONFIG_OK 0x00000008
|
#define ZFCP_STATUS_ADAPTER_XCONFIG_OK 0x00000008
|
||||||
@ -314,4 +315,10 @@ struct zfcp_fsf_req {
|
|||||||
void (*handler)(struct zfcp_fsf_req *);
|
void (*handler)(struct zfcp_fsf_req *);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline
|
||||||
|
int zfcp_adapter_multi_buffer_active(struct zfcp_adapter *adapter)
|
||||||
|
{
|
||||||
|
return atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_MB_ACT;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* ZFCP_DEF_H */
|
#endif /* ZFCP_DEF_H */
|
||||||
|
@ -53,6 +53,7 @@ extern void zfcp_dbf_hba_fsf_uss(char *, struct zfcp_fsf_req *);
|
|||||||
extern void zfcp_dbf_hba_fsf_res(char *, struct zfcp_fsf_req *);
|
extern void zfcp_dbf_hba_fsf_res(char *, struct zfcp_fsf_req *);
|
||||||
extern void zfcp_dbf_hba_bit_err(char *, struct zfcp_fsf_req *);
|
extern void zfcp_dbf_hba_bit_err(char *, struct zfcp_fsf_req *);
|
||||||
extern void zfcp_dbf_hba_berr(struct zfcp_dbf *, struct zfcp_fsf_req *);
|
extern void zfcp_dbf_hba_berr(struct zfcp_dbf *, struct zfcp_fsf_req *);
|
||||||
|
extern void zfcp_dbf_hba_def_err(struct zfcp_adapter *, u64, u16, void **);
|
||||||
extern void zfcp_dbf_san_req(char *, struct zfcp_fsf_req *, u32);
|
extern void zfcp_dbf_san_req(char *, struct zfcp_fsf_req *, u32);
|
||||||
extern void zfcp_dbf_san_res(char *, struct zfcp_fsf_req *);
|
extern void zfcp_dbf_san_res(char *, struct zfcp_fsf_req *);
|
||||||
extern void zfcp_dbf_san_in_els(char *, struct zfcp_fsf_req *);
|
extern void zfcp_dbf_san_in_els(char *, struct zfcp_fsf_req *);
|
||||||
|
@ -936,39 +936,47 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
|
|||||||
struct scatterlist *sg_resp)
|
struct scatterlist *sg_resp)
|
||||||
{
|
{
|
||||||
struct zfcp_adapter *adapter = req->adapter;
|
struct zfcp_adapter *adapter = req->adapter;
|
||||||
|
struct zfcp_qdio *qdio = adapter->qdio;
|
||||||
|
struct fsf_qtcb *qtcb = req->qtcb;
|
||||||
u32 feat = adapter->adapter_features;
|
u32 feat = adapter->adapter_features;
|
||||||
int bytes;
|
|
||||||
|
|
||||||
if (!(feat & FSF_FEATURE_ELS_CT_CHAINED_SBALS)) {
|
if (zfcp_adapter_multi_buffer_active(adapter)) {
|
||||||
if (!zfcp_qdio_sg_one_sbale(sg_req) ||
|
if (zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, sg_req))
|
||||||
!zfcp_qdio_sg_one_sbale(sg_resp))
|
return -EIO;
|
||||||
return -EOPNOTSUPP;
|
if (zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, sg_resp))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
zfcp_fsf_setup_ct_els_unchained(adapter->qdio, &req->qdio_req,
|
zfcp_qdio_set_data_div(qdio, &req->qdio_req,
|
||||||
sg_req, sg_resp);
|
zfcp_qdio_sbale_count(sg_req));
|
||||||
|
zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
|
||||||
|
zfcp_qdio_set_scount(qdio, &req->qdio_req);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* use single, unchained SBAL if it can hold the request */
|
/* use single, unchained SBAL if it can hold the request */
|
||||||
if (zfcp_qdio_sg_one_sbale(sg_req) && zfcp_qdio_sg_one_sbale(sg_resp)) {
|
if (zfcp_qdio_sg_one_sbale(sg_req) && zfcp_qdio_sg_one_sbale(sg_resp)) {
|
||||||
zfcp_fsf_setup_ct_els_unchained(adapter->qdio, &req->qdio_req,
|
zfcp_fsf_setup_ct_els_unchained(qdio, &req->qdio_req,
|
||||||
sg_req, sg_resp);
|
sg_req, sg_resp);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req, sg_req);
|
if (!(feat & FSF_FEATURE_ELS_CT_CHAINED_SBALS))
|
||||||
if (bytes <= 0)
|
return -EOPNOTSUPP;
|
||||||
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);
|
|
||||||
|
|
||||||
bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->qdio_req,
|
if (zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, sg_req))
|
||||||
sg_resp);
|
|
||||||
req->qtcb->bottom.support.resp_buf_length = bytes;
|
|
||||||
if (bytes <= 0)
|
|
||||||
return -EIO;
|
return -EIO;
|
||||||
zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req);
|
|
||||||
|
qtcb->bottom.support.req_buf_length = zfcp_qdio_real_bytes(sg_req);
|
||||||
|
|
||||||
|
zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
|
||||||
|
zfcp_qdio_skip_to_last_sbale(qdio, &req->qdio_req);
|
||||||
|
|
||||||
|
if (zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, sg_resp))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
qtcb->bottom.support.resp_buf_length = zfcp_qdio_real_bytes(sg_resp);
|
||||||
|
|
||||||
|
zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1119,7 +1127,8 @@ int zfcp_fsf_send_els(struct zfcp_adapter *adapter, u32 d_id,
|
|||||||
|
|
||||||
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
|
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
|
||||||
|
|
||||||
zfcp_qdio_sbal_limit(qdio, &req->qdio_req, 2);
|
if (!zfcp_adapter_multi_buffer_active(adapter))
|
||||||
|
zfcp_qdio_sbal_limit(qdio, &req->qdio_req, 2);
|
||||||
|
|
||||||
ret = zfcp_fsf_setup_ct_els(req, els->req, els->resp, timeout);
|
ret = zfcp_fsf_setup_ct_els(req, els->req, els->resp, timeout);
|
||||||
|
|
||||||
@ -2162,7 +2171,7 @@ int zfcp_fsf_fcp_cmnd(struct scsi_cmnd *scsi_cmnd)
|
|||||||
struct zfcp_fsf_req *req;
|
struct zfcp_fsf_req *req;
|
||||||
struct fcp_cmnd *fcp_cmnd;
|
struct fcp_cmnd *fcp_cmnd;
|
||||||
u8 sbtype = SBAL_SFLAGS0_TYPE_READ;
|
u8 sbtype = SBAL_SFLAGS0_TYPE_READ;
|
||||||
int real_bytes, retval = -EIO, dix_bytes = 0;
|
int retval = -EIO;
|
||||||
struct scsi_device *sdev = scsi_cmnd->device;
|
struct scsi_device *sdev = scsi_cmnd->device;
|
||||||
struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
|
struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
|
||||||
struct zfcp_adapter *adapter = zfcp_sdev->port->adapter;
|
struct zfcp_adapter *adapter = zfcp_sdev->port->adapter;
|
||||||
@ -2216,18 +2225,22 @@ int zfcp_fsf_fcp_cmnd(struct scsi_cmnd *scsi_cmnd)
|
|||||||
if (scsi_prot_sg_count(scsi_cmnd)) {
|
if (scsi_prot_sg_count(scsi_cmnd)) {
|
||||||
zfcp_qdio_set_data_div(qdio, &req->qdio_req,
|
zfcp_qdio_set_data_div(qdio, &req->qdio_req,
|
||||||
scsi_prot_sg_count(scsi_cmnd));
|
scsi_prot_sg_count(scsi_cmnd));
|
||||||
dix_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
|
retval = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
|
||||||
|
scsi_prot_sglist(scsi_cmnd));
|
||||||
|
if (retval)
|
||||||
|
goto failed_scsi_cmnd;
|
||||||
|
io->prot_data_length = zfcp_qdio_real_bytes(
|
||||||
scsi_prot_sglist(scsi_cmnd));
|
scsi_prot_sglist(scsi_cmnd));
|
||||||
io->prot_data_length = dix_bytes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
real_bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
|
retval = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req,
|
||||||
scsi_sglist(scsi_cmnd));
|
scsi_sglist(scsi_cmnd));
|
||||||
|
if (unlikely(retval))
|
||||||
if (unlikely(real_bytes < 0) || unlikely(dix_bytes < 0))
|
|
||||||
goto failed_scsi_cmnd;
|
goto failed_scsi_cmnd;
|
||||||
|
|
||||||
zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req);
|
zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req);
|
||||||
|
if (zfcp_adapter_multi_buffer_active(adapter))
|
||||||
|
zfcp_qdio_set_scount(qdio, &req->qdio_req);
|
||||||
|
|
||||||
retval = zfcp_fsf_req_send(req);
|
retval = zfcp_fsf_req_send(req);
|
||||||
if (unlikely(retval))
|
if (unlikely(retval))
|
||||||
@ -2329,7 +2342,7 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
|
|||||||
struct zfcp_qdio *qdio = adapter->qdio;
|
struct zfcp_qdio *qdio = adapter->qdio;
|
||||||
struct zfcp_fsf_req *req = NULL;
|
struct zfcp_fsf_req *req = NULL;
|
||||||
struct fsf_qtcb_bottom_support *bottom;
|
struct fsf_qtcb_bottom_support *bottom;
|
||||||
int retval = -EIO, bytes;
|
int retval = -EIO;
|
||||||
u8 direction;
|
u8 direction;
|
||||||
|
|
||||||
if (!(adapter->adapter_features & FSF_FEATURE_CFDC))
|
if (!(adapter->adapter_features & FSF_FEATURE_CFDC))
|
||||||
@ -2362,13 +2375,17 @@ struct zfcp_fsf_req *zfcp_fsf_control_file(struct zfcp_adapter *adapter,
|
|||||||
bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE;
|
bottom->operation_subtype = FSF_CFDC_OPERATION_SUBTYPE;
|
||||||
bottom->option = fsf_cfdc->option;
|
bottom->option = fsf_cfdc->option;
|
||||||
|
|
||||||
bytes = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, fsf_cfdc->sg);
|
retval = zfcp_qdio_sbals_from_sg(qdio, &req->qdio_req, fsf_cfdc->sg);
|
||||||
|
|
||||||
if (bytes != ZFCP_CFDC_MAX_SIZE) {
|
if (retval ||
|
||||||
|
(zfcp_qdio_real_bytes(fsf_cfdc->sg) != ZFCP_CFDC_MAX_SIZE)) {
|
||||||
zfcp_fsf_req_free(req);
|
zfcp_fsf_req_free(req);
|
||||||
|
retval = -EIO;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
zfcp_qdio_set_sbale_last(adapter->qdio, &req->qdio_req);
|
zfcp_qdio_set_sbale_last(qdio, &req->qdio_req);
|
||||||
|
if (zfcp_adapter_multi_buffer_active(adapter))
|
||||||
|
zfcp_qdio_set_scount(qdio, &req->qdio_req);
|
||||||
|
|
||||||
zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
|
zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT);
|
||||||
retval = zfcp_fsf_req_send(req);
|
retval = zfcp_fsf_req_send(req);
|
||||||
|
@ -15,6 +15,10 @@
|
|||||||
|
|
||||||
#define QBUFF_PER_PAGE (PAGE_SIZE / sizeof(struct qdio_buffer))
|
#define QBUFF_PER_PAGE (PAGE_SIZE / sizeof(struct qdio_buffer))
|
||||||
|
|
||||||
|
static bool enable_multibuffer;
|
||||||
|
module_param_named(datarouter, enable_multibuffer, bool, 0400);
|
||||||
|
MODULE_PARM_DESC(datarouter, "Enable hardware data router support");
|
||||||
|
|
||||||
static int zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbal)
|
static int zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbal)
|
||||||
{
|
{
|
||||||
int pos;
|
int pos;
|
||||||
@ -37,8 +41,11 @@ static void zfcp_qdio_handler_error(struct zfcp_qdio *qdio, char *id,
|
|||||||
|
|
||||||
dev_warn(&adapter->ccw_device->dev, "A QDIO problem occurred\n");
|
dev_warn(&adapter->ccw_device->dev, "A QDIO problem occurred\n");
|
||||||
|
|
||||||
if (qdio_err & QDIO_ERROR_SLSB_STATE)
|
if (qdio_err & QDIO_ERROR_SLSB_STATE) {
|
||||||
zfcp_qdio_siosl(adapter);
|
zfcp_qdio_siosl(adapter);
|
||||||
|
zfcp_erp_adapter_shutdown(adapter, 0, id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
zfcp_erp_adapter_reopen(adapter,
|
zfcp_erp_adapter_reopen(adapter,
|
||||||
ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
|
ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED |
|
||||||
ZFCP_STATUS_COMMON_ERP_FAILED, id);
|
ZFCP_STATUS_COMMON_ERP_FAILED, id);
|
||||||
@ -93,9 +100,27 @@ static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err,
|
|||||||
unsigned long parm)
|
unsigned long parm)
|
||||||
{
|
{
|
||||||
struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm;
|
struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm;
|
||||||
int sbal_idx, sbal_no;
|
struct zfcp_adapter *adapter = qdio->adapter;
|
||||||
|
struct qdio_buffer_element *sbale;
|
||||||
|
int sbal_no, sbal_idx;
|
||||||
|
void *pl[ZFCP_QDIO_MAX_SBALS_PER_REQ + 1];
|
||||||
|
u64 req_id;
|
||||||
|
u8 scount;
|
||||||
|
|
||||||
if (unlikely(qdio_err)) {
|
if (unlikely(qdio_err)) {
|
||||||
|
memset(pl, 0, ZFCP_QDIO_MAX_SBALS_PER_REQ * sizeof(void *));
|
||||||
|
if (zfcp_adapter_multi_buffer_active(adapter)) {
|
||||||
|
sbale = qdio->res_q[idx]->element;
|
||||||
|
req_id = (u64) sbale->addr;
|
||||||
|
scount = sbale->scount + 1; /* incl. signaling SBAL */
|
||||||
|
|
||||||
|
for (sbal_no = 0; sbal_no < scount; sbal_no++) {
|
||||||
|
sbal_idx = (idx + sbal_no) %
|
||||||
|
QDIO_MAX_BUFFERS_PER_Q;
|
||||||
|
pl[sbal_no] = qdio->res_q[sbal_idx];
|
||||||
|
}
|
||||||
|
zfcp_dbf_hba_def_err(adapter, req_id, scount, pl);
|
||||||
|
}
|
||||||
zfcp_qdio_handler_error(qdio, "qdires1", qdio_err);
|
zfcp_qdio_handler_error(qdio, "qdires1", qdio_err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -155,7 +180,7 @@ zfcp_qdio_sbal_chain(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
|
|||||||
static struct qdio_buffer_element *
|
static struct qdio_buffer_element *
|
||||||
zfcp_qdio_sbale_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
|
zfcp_qdio_sbale_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
|
||||||
{
|
{
|
||||||
if (q_req->sbale_curr == ZFCP_QDIO_LAST_SBALE_PER_SBAL)
|
if (q_req->sbale_curr == qdio->max_sbale_per_sbal - 1)
|
||||||
return zfcp_qdio_sbal_chain(qdio, q_req);
|
return zfcp_qdio_sbal_chain(qdio, q_req);
|
||||||
q_req->sbale_curr++;
|
q_req->sbale_curr++;
|
||||||
return zfcp_qdio_sbale_curr(qdio, q_req);
|
return zfcp_qdio_sbale_curr(qdio, q_req);
|
||||||
@ -167,13 +192,12 @@ zfcp_qdio_sbale_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
|
|||||||
* @q_req: pointer to struct zfcp_qdio_req
|
* @q_req: pointer to struct zfcp_qdio_req
|
||||||
* @sg: scatter-gather list
|
* @sg: scatter-gather list
|
||||||
* @max_sbals: upper bound for number of SBALs to be used
|
* @max_sbals: upper bound for number of SBALs to be used
|
||||||
* Returns: number of bytes, or error (negativ)
|
* Returns: zero or -EINVAL on error
|
||||||
*/
|
*/
|
||||||
int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
|
int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
|
||||||
struct scatterlist *sg)
|
struct scatterlist *sg)
|
||||||
{
|
{
|
||||||
struct qdio_buffer_element *sbale;
|
struct qdio_buffer_element *sbale;
|
||||||
int bytes = 0;
|
|
||||||
|
|
||||||
/* set storage-block type for this request */
|
/* set storage-block type for this request */
|
||||||
sbale = zfcp_qdio_sbale_req(qdio, q_req);
|
sbale = zfcp_qdio_sbale_req(qdio, q_req);
|
||||||
@ -187,14 +211,10 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
|
|||||||
q_req->sbal_number);
|
q_req->sbal_number);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
sbale->addr = sg_virt(sg);
|
sbale->addr = sg_virt(sg);
|
||||||
sbale->length = sg->length;
|
sbale->length = sg->length;
|
||||||
|
|
||||||
bytes += sg->length;
|
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
return bytes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int zfcp_qdio_sbal_check(struct zfcp_qdio *qdio)
|
static int zfcp_qdio_sbal_check(struct zfcp_qdio *qdio)
|
||||||
@ -283,6 +303,8 @@ static void zfcp_qdio_setup_init_data(struct qdio_initialize *id,
|
|||||||
memcpy(id->adapter_name, dev_name(&id->cdev->dev), 8);
|
memcpy(id->adapter_name, dev_name(&id->cdev->dev), 8);
|
||||||
ASCEBC(id->adapter_name, 8);
|
ASCEBC(id->adapter_name, 8);
|
||||||
id->qib_rflags = QIB_RFLAGS_ENABLE_DATA_DIV;
|
id->qib_rflags = QIB_RFLAGS_ENABLE_DATA_DIV;
|
||||||
|
if (enable_multibuffer)
|
||||||
|
id->qdr_ac |= QDR_AC_MULTI_BUFFER_ENABLE;
|
||||||
id->no_input_qs = 1;
|
id->no_input_qs = 1;
|
||||||
id->no_output_qs = 1;
|
id->no_output_qs = 1;
|
||||||
id->input_handler = zfcp_qdio_int_resp;
|
id->input_handler = zfcp_qdio_int_resp;
|
||||||
@ -378,6 +400,17 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio)
|
|||||||
atomic_set_mask(ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED,
|
atomic_set_mask(ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED,
|
||||||
&qdio->adapter->status);
|
&qdio->adapter->status);
|
||||||
|
|
||||||
|
if (ssqd.qdioac2 & CHSC_AC2_MULTI_BUFFER_ENABLED) {
|
||||||
|
atomic_set_mask(ZFCP_STATUS_ADAPTER_MB_ACT, &adapter->status);
|
||||||
|
qdio->max_sbale_per_sbal = QDIO_MAX_ELEMENTS_PER_BUFFER;
|
||||||
|
} else {
|
||||||
|
atomic_clear_mask(ZFCP_STATUS_ADAPTER_MB_ACT, &adapter->status);
|
||||||
|
qdio->max_sbale_per_sbal = QDIO_MAX_ELEMENTS_PER_BUFFER - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
qdio->max_sbale_per_req =
|
||||||
|
ZFCP_QDIO_MAX_SBALS_PER_REQ * qdio->max_sbale_per_sbal
|
||||||
|
- 2;
|
||||||
if (qdio_activate(cdev))
|
if (qdio_activate(cdev))
|
||||||
goto failed_qdio;
|
goto failed_qdio;
|
||||||
|
|
||||||
@ -397,6 +430,11 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio)
|
|||||||
atomic_set(&qdio->req_q_free, QDIO_MAX_BUFFERS_PER_Q);
|
atomic_set(&qdio->req_q_free, QDIO_MAX_BUFFERS_PER_Q);
|
||||||
atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &qdio->adapter->status);
|
atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &qdio->adapter->status);
|
||||||
|
|
||||||
|
if (adapter->scsi_host) {
|
||||||
|
adapter->scsi_host->sg_tablesize = qdio->max_sbale_per_req;
|
||||||
|
adapter->scsi_host->max_sectors = qdio->max_sbale_per_req * 8;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
failed_qdio:
|
failed_qdio:
|
||||||
|
@ -13,20 +13,9 @@
|
|||||||
|
|
||||||
#define ZFCP_QDIO_SBALE_LEN PAGE_SIZE
|
#define ZFCP_QDIO_SBALE_LEN PAGE_SIZE
|
||||||
|
|
||||||
/* DMQ bug workaround: don't use last SBALE */
|
|
||||||
#define ZFCP_QDIO_MAX_SBALES_PER_SBAL (QDIO_MAX_ELEMENTS_PER_BUFFER - 1)
|
|
||||||
|
|
||||||
/* index of last SBALE (with respect to DMQ bug workaround) */
|
|
||||||
#define ZFCP_QDIO_LAST_SBALE_PER_SBAL (ZFCP_QDIO_MAX_SBALES_PER_SBAL - 1)
|
|
||||||
|
|
||||||
/* Max SBALS for chaining */
|
/* Max SBALS for chaining */
|
||||||
#define ZFCP_QDIO_MAX_SBALS_PER_REQ 36
|
#define ZFCP_QDIO_MAX_SBALS_PER_REQ 36
|
||||||
|
|
||||||
/* max. number of (data buffer) SBALEs in largest SBAL chain
|
|
||||||
* request ID + QTCB in SBALE 0 + 1 of first SBAL in chain */
|
|
||||||
#define ZFCP_QDIO_MAX_SBALES_PER_REQ \
|
|
||||||
(ZFCP_QDIO_MAX_SBALS_PER_REQ * ZFCP_QDIO_MAX_SBALES_PER_SBAL - 2)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct zfcp_qdio - basic qdio data structure
|
* struct zfcp_qdio - basic qdio data structure
|
||||||
* @res_q: response queue
|
* @res_q: response queue
|
||||||
@ -53,6 +42,8 @@ struct zfcp_qdio {
|
|||||||
atomic_t req_q_full;
|
atomic_t req_q_full;
|
||||||
wait_queue_head_t req_q_wq;
|
wait_queue_head_t req_q_wq;
|
||||||
struct zfcp_adapter *adapter;
|
struct zfcp_adapter *adapter;
|
||||||
|
u16 max_sbale_per_sbal;
|
||||||
|
u16 max_sbale_per_req;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -155,7 +146,7 @@ void zfcp_qdio_fill_next(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req,
|
|||||||
{
|
{
|
||||||
struct qdio_buffer_element *sbale;
|
struct qdio_buffer_element *sbale;
|
||||||
|
|
||||||
BUG_ON(q_req->sbale_curr == ZFCP_QDIO_LAST_SBALE_PER_SBAL);
|
BUG_ON(q_req->sbale_curr == qdio->max_sbale_per_sbal - 1);
|
||||||
q_req->sbale_curr++;
|
q_req->sbale_curr++;
|
||||||
sbale = zfcp_qdio_sbale_curr(qdio, q_req);
|
sbale = zfcp_qdio_sbale_curr(qdio, q_req);
|
||||||
sbale->addr = data;
|
sbale->addr = data;
|
||||||
@ -195,9 +186,10 @@ int zfcp_qdio_sg_one_sbale(struct scatterlist *sg)
|
|||||||
* @q_req: The current zfcp_qdio_req
|
* @q_req: The current zfcp_qdio_req
|
||||||
*/
|
*/
|
||||||
static inline
|
static inline
|
||||||
void zfcp_qdio_skip_to_last_sbale(struct zfcp_qdio_req *q_req)
|
void zfcp_qdio_skip_to_last_sbale(struct zfcp_qdio *qdio,
|
||||||
|
struct zfcp_qdio_req *q_req)
|
||||||
{
|
{
|
||||||
q_req->sbale_curr = ZFCP_QDIO_LAST_SBALE_PER_SBAL;
|
q_req->sbale_curr = qdio->max_sbale_per_sbal - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -228,8 +220,52 @@ void zfcp_qdio_set_data_div(struct zfcp_qdio *qdio,
|
|||||||
{
|
{
|
||||||
struct qdio_buffer_element *sbale;
|
struct qdio_buffer_element *sbale;
|
||||||
|
|
||||||
sbale = &qdio->req_q[q_req->sbal_first]->element[0];
|
sbale = qdio->req_q[q_req->sbal_first]->element;
|
||||||
sbale->length = count;
|
sbale->length = count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zfcp_qdio_sbale_count - count sbale used
|
||||||
|
* @sg: pointer to struct scatterlist
|
||||||
|
*/
|
||||||
|
static inline
|
||||||
|
unsigned int zfcp_qdio_sbale_count(struct scatterlist *sg)
|
||||||
|
{
|
||||||
|
unsigned int count = 0;
|
||||||
|
|
||||||
|
for (; sg; sg = sg_next(sg))
|
||||||
|
count++;
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zfcp_qdio_real_bytes - count bytes used
|
||||||
|
* @sg: pointer to struct scatterlist
|
||||||
|
*/
|
||||||
|
static inline
|
||||||
|
unsigned int zfcp_qdio_real_bytes(struct scatterlist *sg)
|
||||||
|
{
|
||||||
|
unsigned int real_bytes = 0;
|
||||||
|
|
||||||
|
for (; sg; sg = sg_next(sg))
|
||||||
|
real_bytes += sg->length;
|
||||||
|
|
||||||
|
return real_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zfcp_qdio_set_scount - set SBAL count value
|
||||||
|
* @qdio: pointer to struct zfcp_qdio
|
||||||
|
* @q_req: The current zfcp_qdio_req
|
||||||
|
*/
|
||||||
|
static inline
|
||||||
|
void zfcp_qdio_set_scount(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req)
|
||||||
|
{
|
||||||
|
struct qdio_buffer_element *sbale;
|
||||||
|
|
||||||
|
sbale = qdio->req_q[q_req->sbal_first]->element;
|
||||||
|
sbale->scount = q_req->sbal_number - 1;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* ZFCP_QDIO_H */
|
#endif /* ZFCP_QDIO_H */
|
||||||
|
@ -306,8 +306,8 @@ static struct scsi_host_template zfcp_scsi_host_template = {
|
|||||||
.proc_name = "zfcp",
|
.proc_name = "zfcp",
|
||||||
.can_queue = 4096,
|
.can_queue = 4096,
|
||||||
.this_id = -1,
|
.this_id = -1,
|
||||||
.sg_tablesize = ZFCP_QDIO_MAX_SBALES_PER_REQ,
|
.sg_tablesize = 1, /* adjusted later */
|
||||||
.max_sectors = (ZFCP_QDIO_MAX_SBALES_PER_REQ * 8),
|
.max_sectors = 8, /* adjusted later */
|
||||||
.dma_boundary = ZFCP_QDIO_SBALE_LEN - 1,
|
.dma_boundary = ZFCP_QDIO_SBALE_LEN - 1,
|
||||||
.cmd_per_lun = 1,
|
.cmd_per_lun = 1,
|
||||||
.use_clustering = 1,
|
.use_clustering = 1,
|
||||||
@ -665,9 +665,9 @@ void zfcp_scsi_set_prot(struct zfcp_adapter *adapter)
|
|||||||
adapter->adapter_features & FSF_FEATURE_DIX_PROT_TCPIP) {
|
adapter->adapter_features & FSF_FEATURE_DIX_PROT_TCPIP) {
|
||||||
mask |= SHOST_DIX_TYPE1_PROTECTION;
|
mask |= SHOST_DIX_TYPE1_PROTECTION;
|
||||||
scsi_host_set_guard(shost, SHOST_DIX_GUARD_IP);
|
scsi_host_set_guard(shost, SHOST_DIX_GUARD_IP);
|
||||||
shost->sg_prot_tablesize = ZFCP_QDIO_MAX_SBALES_PER_REQ / 2;
|
shost->sg_prot_tablesize = adapter->qdio->max_sbale_per_req / 2;
|
||||||
shost->sg_tablesize = ZFCP_QDIO_MAX_SBALES_PER_REQ / 2;
|
shost->sg_tablesize = adapter->qdio->max_sbale_per_req / 2;
|
||||||
shost->max_sectors = ZFCP_QDIO_MAX_SBALES_PER_REQ * 8 / 2;
|
shost->max_sectors = shost->sg_tablesize * 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
scsi_host_set_prot(shost, mask);
|
scsi_host_set_prot(shost, mask);
|
||||||
|
Loading…
Reference in New Issue
Block a user