Merge 6cbcc7ab21 ("Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi") into android-mainline

Steps on the way to 5.16-rc1

Resolves conflicts in:
	drivers/scsi/ufs/ufshcd.c
	drivers/scsi/ufs/ufshcd.h

Will not build due to a static_assert() in the ufs code that will be
reverted in a later commit.

Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Change-Id: I244662dad7bb84192c0762af96b53111375fa6c4
This commit is contained in:
Greg Kroah-Hartman
2021-11-16 19:13:31 +01:00
34 changed files with 913 additions and 377 deletions

View File

@@ -4145,7 +4145,7 @@ static int
sli_get_read_config(struct sli4 *sli4)
{
struct sli4_rsp_read_config *conf = sli4->bmbx.virt;
u32 i, total, total_size;
u32 i, total;
u32 *base;
if (sli_cmd_read_config(sli4, sli4->bmbx.virt)) {
@@ -4203,8 +4203,7 @@ sli_get_read_config(struct sli4 *sli4)
for (i = 0; i < SLI4_RSRC_MAX; i++) {
total = sli4->ext[i].number * sli4->ext[i].size;
total_size = BITS_TO_LONGS(total) * sizeof(long);
sli4->ext[i].use_map = kzalloc(total_size, GFP_KERNEL);
sli4->ext[i].use_map = bitmap_zalloc(total, GFP_KERNEL);
if (!sli4->ext[i].use_map) {
efc_log_err(sli4, "bitmap memory allocation failed %d\n",
i);
@@ -4743,7 +4742,7 @@ sli_reset(struct sli4 *sli4)
sli4->ext[0].base = NULL;
for (i = 0; i < SLI4_RSRC_MAX; i++) {
kfree(sli4->ext[i].use_map);
bitmap_free(sli4->ext[i].use_map);
sli4->ext[i].use_map = NULL;
sli4->ext[i].base = NULL;
}
@@ -4784,7 +4783,7 @@ sli_teardown(struct sli4 *sli4)
for (i = 0; i < SLI4_RSRC_MAX; i++) {
sli4->ext[i].base = NULL;
kfree(sli4->ext[i].use_map);
bitmap_free(sli4->ext[i].use_map);
sli4->ext[i].use_map = NULL;
}

View File

@@ -388,6 +388,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
shost->shost_state = SHOST_CREATED;
INIT_LIST_HEAD(&shost->__devices);
INIT_LIST_HEAD(&shost->__targets);
INIT_LIST_HEAD(&shost->eh_abort_list);
INIT_LIST_HEAD(&shost->eh_cmd_q);
INIT_LIST_HEAD(&shost->starved_list);
init_waitqueue_head(&shost->host_wait);

View File

@@ -2762,7 +2762,12 @@ qla2x00_terminate_rport_io(struct fc_rport *rport)
if (fcport->loop_id != FC_NO_LOOP_ID)
fcport->logout_on_delete = 1;
qlt_schedule_sess_for_deletion(fcport);
if (!EDIF_NEGOTIATION_PENDING(fcport)) {
ql_dbg(ql_dbg_disc, fcport->vha, 0x911e,
"%s %d schedule session deletion\n", __func__,
__LINE__);
qlt_schedule_sess_for_deletion(fcport);
}
} else {
qla2x00_port_logout(fcport->vha, fcport);
}

View File

@@ -639,9 +639,9 @@ struct qla_els_pt_arg {
u8 els_opcode;
u8 vp_idx;
__le16 nport_handle;
u16 control_flags;
u16 control_flags, ox_id;
__le32 rx_xchg_address;
port_id_t did;
port_id_t did, sid;
u32 tx_len, tx_byte_count, rx_len, rx_byte_count;
dma_addr_t tx_addr, rx_addr;

View File

@@ -218,7 +218,7 @@ fc_port_t *fcport)
"%s edif not enabled\n", __func__);
goto done;
}
if (vha->e_dbell.db_flags != EDB_ACTIVE) {
if (DBELL_INACTIVE(vha)) {
ql_dbg(ql_dbg_edif, vha, 0x09102,
"%s doorbell not enabled\n", __func__);
goto done;
@@ -290,63 +290,6 @@ qla_edif_app_check(scsi_qla_host_t *vha, struct app_id appid)
return false;
}
static void qla_edif_reset_auth_wait(struct fc_port *fcport, int state,
int waitonly)
{
int cnt, max_cnt = 200;
bool traced = false;
fcport->keep_nport_handle = 1;
if (!waitonly) {
qla2x00_set_fcport_disc_state(fcport, state);
qlt_schedule_sess_for_deletion(fcport);
} else {
qla2x00_set_fcport_disc_state(fcport, state);
}
ql_dbg(ql_dbg_edif, fcport->vha, 0xf086,
"%s: waiting for session, max_cnt=%u\n",
__func__, max_cnt);
cnt = 0;
if (waitonly) {
/* Marker wait min 10 msecs. */
msleep(50);
cnt += 50;
}
while (1) {
if (!traced) {
ql_dbg(ql_dbg_edif, fcport->vha, 0xf086,
"%s: session sleep.\n",
__func__);
traced = true;
}
msleep(20);
cnt++;
if (waitonly && (fcport->disc_state == state ||
fcport->disc_state == DSC_LOGIN_COMPLETE))
break;
if (fcport->disc_state == DSC_LOGIN_AUTH_PEND)
break;
if (cnt > max_cnt)
break;
}
if (!waitonly) {
ql_dbg(ql_dbg_edif, fcport->vha, 0xf086,
"%s: waited for session - %8phC, loopid=%x portid=%06x fcport=%p state=%u, cnt=%u\n",
__func__, fcport->port_name, fcport->loop_id,
fcport->d_id.b24, fcport, fcport->disc_state, cnt);
} else {
ql_dbg(ql_dbg_edif, fcport->vha, 0xf086,
"%s: waited ONLY for session - %8phC, loopid=%x portid=%06x fcport=%p state=%u, cnt=%u\n",
__func__, fcport->port_name, fcport->loop_id,
fcport->d_id.b24, fcport, fcport->disc_state, cnt);
}
}
static void
qla_edif_free_sa_ctl(fc_port_t *fcport, struct edif_sa_ctl *sa_ctl,
int index)
@@ -529,7 +472,8 @@ qla_edif_app_start(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
struct app_start_reply appreply;
struct fc_port *fcport, *tf;
ql_dbg(ql_dbg_edif, vha, 0x911d, "%s app start\n", __func__);
ql_log(ql_log_info, vha, 0x1313,
"EDIF application registration with driver, FC device connections will be re-established.\n");
sg_copy_to_buffer(bsg_job->request_payload.sg_list,
bsg_job->request_payload.sg_cnt, &appstart,
@@ -538,9 +482,9 @@ qla_edif_app_start(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
ql_dbg(ql_dbg_edif, vha, 0x911d, "%s app_vid=%x app_start_flags %x\n",
__func__, appstart.app_info.app_vid, appstart.app_start_flags);
if (vha->e_dbell.db_flags != EDB_ACTIVE) {
if (DBELL_INACTIVE(vha)) {
/* mark doorbell as active since an app is now present */
vha->e_dbell.db_flags = EDB_ACTIVE;
vha->e_dbell.db_flags |= EDB_ACTIVE;
} else {
ql_dbg(ql_dbg_edif, vha, 0x911e, "%s doorbell already active\n",
__func__);
@@ -554,37 +498,36 @@ qla_edif_app_start(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
qla2xxx_wake_dpc(vha);
} else {
list_for_each_entry_safe(fcport, tf, &vha->vp_fcports, list) {
ql_dbg(ql_dbg_edif, vha, 0x2058,
"FCSP - nn %8phN pn %8phN portid=%06x.\n",
fcport->node_name, fcport->port_name,
fcport->d_id.b24);
ql_dbg(ql_dbg_edif, vha, 0xf084,
"%s: sess %p %8phC lid %#04x s_id %06x logout %d\n",
__func__, fcport, fcport->port_name,
fcport->loop_id, fcport->d_id.b24,
fcport->logout_on_delete);
ql_dbg(ql_dbg_edif, vha, 0xf084,
"keep %d els_logo %d disc state %d auth state %d stop state %d\n",
fcport->keep_nport_handle,
fcport->send_els_logo, fcport->disc_state,
fcport->edif.auth_state, fcport->edif.app_stop);
"%s: se_sess %p / sess %p from port %8phC "
"loop_id %#04x s_id %06x logout %d "
"keep %d els_logo %d disc state %d auth state %d"
"stop state %d\n",
__func__, fcport->se_sess, fcport,
fcport->port_name, fcport->loop_id,
fcport->d_id.b24, fcport->logout_on_delete,
fcport->keep_nport_handle, fcport->send_els_logo,
fcport->disc_state, fcport->edif.auth_state,
fcport->edif.app_stop);
if (atomic_read(&vha->loop_state) == LOOP_DOWN)
break;
if (!(fcport->flags & FCF_FCSP_DEVICE))
continue;
fcport->edif.app_started = 1;
if (fcport->edif.app_stop ||
(fcport->disc_state != DSC_LOGIN_COMPLETE &&
fcport->disc_state != DSC_LOGIN_PEND &&
fcport->disc_state != DSC_DELETED)) {
/* no activity */
fcport->edif.app_stop = 0;
fcport->login_retry = vha->hw->login_retry_count;
ql_dbg(ql_dbg_edif, vha, 0x911e,
"%s wwpn %8phC calling qla_edif_reset_auth_wait\n",
__func__, fcport->port_name);
fcport->edif.app_sess_online = 1;
qla_edif_reset_auth_wait(fcport, DSC_LOGIN_PEND, 0);
}
/* no activity */
fcport->edif.app_stop = 0;
ql_dbg(ql_dbg_edif, vha, 0x911e,
"%s wwpn %8phC calling qla_edif_reset_auth_wait\n",
__func__, fcport->port_name);
fcport->edif.app_sess_online = 0;
qlt_schedule_sess_for_deletion(fcport);
qla_edif_sa_ctl_init(vha, fcport);
}
}
@@ -601,14 +544,14 @@ qla_edif_app_start(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
appreply.edif_enode_active = vha->pur_cinfo.enode_flags;
appreply.edif_edb_active = vha->e_dbell.db_flags;
bsg_job->reply_len = sizeof(struct fc_bsg_reply) +
sizeof(struct app_start_reply);
bsg_job->reply_len = sizeof(struct fc_bsg_reply);
SET_DID_STATUS(bsg_reply->result, DID_OK);
sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
bsg_job->reply_payload.sg_cnt, &appreply,
sizeof(struct app_start_reply));
bsg_reply->reply_payload_rcv_len = sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
bsg_job->reply_payload.sg_cnt,
&appreply,
sizeof(struct app_start_reply));
ql_dbg(ql_dbg_edif, vha, 0x911d,
"%s app start completed with 0x%x\n",
@@ -800,15 +743,15 @@ qla_edif_app_authok(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
ql_dbg(ql_dbg_edif, vha, 0x911e,
"%s AUTH complete - RESUME with prli for wwpn %8phC\n",
__func__, fcport->port_name);
qla_edif_reset_auth_wait(fcport, DSC_LOGIN_PEND, 1);
qla24xx_post_prli_work(vha, fcport);
}
errstate_exit:
bsg_job->reply_len = sizeof(struct fc_bsg_reply);
sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
bsg_job->reply_payload.sg_cnt, &appplogireply,
sizeof(struct app_plogi_reply));
bsg_reply->reply_payload_rcv_len = sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
bsg_job->reply_payload.sg_cnt,
&appplogireply,
sizeof(struct app_plogi_reply));
return rval;
}
@@ -873,7 +816,7 @@ qla_edif_app_authfail(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
if (qla_ini_mode_enabled(fcport->vha)) {
fcport->send_els_logo = 1;
qla_edif_reset_auth_wait(fcport, DSC_LOGIN_PEND, 0);
qlt_schedule_sess_for_deletion(fcport);
}
}
@@ -891,7 +834,7 @@ static int
qla_edif_app_getfcinfo(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
{
int32_t rval = 0;
int32_t num_cnt;
int32_t pcnt = 0;
struct fc_bsg_reply *bsg_reply = bsg_job->reply;
struct app_pinfo_req app_req;
struct app_pinfo_reply *app_reply;
@@ -903,16 +846,14 @@ qla_edif_app_getfcinfo(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
bsg_job->request_payload.sg_cnt, &app_req,
sizeof(struct app_pinfo_req));
num_cnt = app_req.num_ports; /* num of ports alloc'd by app */
app_reply = kzalloc((sizeof(struct app_pinfo_reply) +
sizeof(struct app_pinfo) * num_cnt), GFP_KERNEL);
sizeof(struct app_pinfo) * app_req.num_ports), GFP_KERNEL);
if (!app_reply) {
SET_DID_STATUS(bsg_reply->result, DID_ERROR);
rval = -1;
} else {
struct fc_port *fcport = NULL, *tf;
uint32_t pcnt = 0;
list_for_each_entry_safe(fcport, tf, &vha->vp_fcports, list) {
if (!(fcport->flags & FCF_FCSP_DEVICE))
@@ -981,9 +922,11 @@ qla_edif_app_getfcinfo(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
SET_DID_STATUS(bsg_reply->result, DID_OK);
}
sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
bsg_job->reply_payload.sg_cnt, app_reply,
sizeof(struct app_pinfo_reply) + sizeof(struct app_pinfo) * num_cnt);
bsg_job->reply_len = sizeof(struct fc_bsg_reply);
bsg_reply->reply_payload_rcv_len = sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
bsg_job->reply_payload.sg_cnt,
app_reply,
sizeof(struct app_pinfo_reply) + sizeof(struct app_pinfo) * pcnt);
kfree(app_reply);
@@ -1000,10 +943,11 @@ qla_edif_app_getstats(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
{
int32_t rval = 0;
struct fc_bsg_reply *bsg_reply = bsg_job->reply;
uint32_t ret_size, size;
uint32_t size;
struct app_sinfo_req app_req;
struct app_stats_reply *app_reply;
uint32_t pcnt = 0;
sg_copy_to_buffer(bsg_job->request_payload.sg_list,
bsg_job->request_payload.sg_cnt, &app_req,
@@ -1019,18 +963,12 @@ qla_edif_app_getstats(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
size = sizeof(struct app_stats_reply) +
(sizeof(struct app_sinfo) * app_req.num_ports);
if (size > bsg_job->reply_payload.payload_len)
ret_size = bsg_job->reply_payload.payload_len;
else
ret_size = size;
app_reply = kzalloc(size, GFP_KERNEL);
if (!app_reply) {
SET_DID_STATUS(bsg_reply->result, DID_ERROR);
rval = -1;
} else {
struct fc_port *fcport = NULL, *tf;
uint32_t pcnt = 0;
list_for_each_entry_safe(fcport, tf, &vha->vp_fcports, list) {
if (fcport->edif.enable) {
@@ -1054,9 +992,11 @@ qla_edif_app_getstats(scsi_qla_host_t *vha, struct bsg_job *bsg_job)
SET_DID_STATUS(bsg_reply->result, DID_OK);
}
bsg_job->reply_len = sizeof(struct fc_bsg_reply);
bsg_reply->reply_payload_rcv_len =
sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
bsg_job->reply_payload.sg_cnt, app_reply, ret_size);
bsg_job->reply_payload.sg_cnt, app_reply,
sizeof(struct app_stats_reply) + (sizeof(struct app_sinfo) * pcnt));
kfree(app_reply);
@@ -1130,8 +1070,7 @@ qla_edif_app_mgmt(struct bsg_job *bsg_job)
__func__,
bsg_request->rqst_data.h_vendor.vendor_cmd[1]);
rval = EXT_STATUS_INVALID_PARAM;
bsg_job->reply_len = sizeof(struct fc_bsg_reply);
SET_DID_STATUS(bsg_reply->result, DID_ERROR);
done = false;
break;
}
@@ -1330,7 +1269,7 @@ qla24xx_sadb_update(struct bsg_job *bsg_job)
goto done;
}
if (vha->e_dbell.db_flags != EDB_ACTIVE) {
if (DBELL_INACTIVE(vha)) {
ql_log(ql_log_warn, vha, 0x70a1, "App not started\n");
rval = -EIO;
SET_DID_STATUS(bsg_reply->result, DID_ERROR);
@@ -1651,6 +1590,40 @@ qla_enode_stop(scsi_qla_host_t *vha)
spin_unlock_irqrestore(&vha->pur_cinfo.pur_lock, flags);
}
static void qla_enode_clear(scsi_qla_host_t *vha, port_id_t portid)
{
unsigned long flags;
struct enode *e, *tmp;
struct purexevent *purex;
LIST_HEAD(enode_list);
if (vha->pur_cinfo.enode_flags != ENODE_ACTIVE) {
ql_dbg(ql_dbg_edif, vha, 0x09102,
"%s enode not active\n", __func__);
return;
}
spin_lock_irqsave(&vha->pur_cinfo.pur_lock, flags);
list_for_each_entry_safe(e, tmp, &vha->pur_cinfo.head, list) {
purex = &e->u.purexinfo;
if (purex->pur_info.pur_sid.b24 == portid.b24) {
ql_dbg(ql_dbg_edif, vha, 0x911d,
"%s free ELS sid=%06x. xchg %x, nb=%xh\n",
__func__, portid.b24,
purex->pur_info.pur_rx_xchg_address,
purex->pur_info.pur_bytes_rcvd);
list_del_init(&e->list);
list_add_tail(&e->list, &enode_list);
}
}
spin_unlock_irqrestore(&vha->pur_cinfo.pur_lock, flags);
list_for_each_entry_safe(e, tmp, &enode_list, list) {
list_del_init(&e->list);
qla_enode_free(vha, e);
}
}
/*
* allocate enode struct and populate buffer
* returns: enode pointer with buffers
@@ -1695,41 +1668,25 @@ static struct enode *
qla_enode_find(scsi_qla_host_t *vha, uint32_t ntype, uint32_t p1, uint32_t p2)
{
struct enode *node_rtn = NULL;
struct enode *list_node = NULL;
struct enode *list_node, *q;
unsigned long flags;
struct list_head *pos, *q;
uint32_t sid;
uint32_t rw_flag;
struct purexevent *purex;
/* secure the list from moving under us */
spin_lock_irqsave(&vha->pur_cinfo.pur_lock, flags);
list_for_each_safe(pos, q, &vha->pur_cinfo.head) {
list_node = list_entry(pos, struct enode, list);
list_for_each_entry_safe(list_node, q, &vha->pur_cinfo.head, list) {
/* node type determines what p1 and p2 are */
purex = &list_node->u.purexinfo;
sid = p1;
rw_flag = p2;
if (purex->pur_info.pur_sid.b24 == sid) {
if (purex->pur_info.pur_pend == 1 &&
rw_flag == PUR_GET) {
/*
* if the receive is in progress
* and its a read/get then can't
* transfer yet
*/
ql_dbg(ql_dbg_edif, vha, 0x9106,
"%s purex xfer in progress for sid=%x\n",
__func__, sid);
} else {
/* found it and its complete */
node_rtn = list_node;
list_del(pos);
break;
}
/* found it and its complete */
node_rtn = list_node;
list_del(&list_node->list);
break;
}
}
@@ -1802,7 +1759,8 @@ qla_els_reject_iocb(scsi_qla_host_t *vha, struct qla_qpair *qp,
qla_els_pt_iocb(vha, els_iocb, a);
ql_dbg(ql_dbg_edif, vha, 0x0183,
"Sending ELS reject...\n");
"Sending ELS reject ox_id %04x s:%06x -> d:%06x\n",
a->ox_id, a->sid.b24, a->did.b24);
ql_dump_buffer(ql_dbg_edif + ql_dbg_verbose, vha, 0x0185,
vha->hw->elsrej.c, sizeof(*vha->hw->elsrej.c));
/* flush iocb to mem before notifying hw doorbell */
@@ -1814,7 +1772,7 @@ qla_els_reject_iocb(scsi_qla_host_t *vha, struct qla_qpair *qp,
void
qla_edb_init(scsi_qla_host_t *vha)
{
if (vha->e_dbell.db_flags == EDB_ACTIVE) {
if (DBELL_ACTIVE(vha)) {
/* list already init'd - error */
ql_dbg(ql_dbg_edif, vha, 0x09102,
"edif db already initialized, cannot reinit\n");
@@ -1850,6 +1808,57 @@ qla_edb_node_free(scsi_qla_host_t *vha, struct edb_node *node)
node->ntype = N_UNDEF;
}
static void qla_edb_clear(scsi_qla_host_t *vha, port_id_t portid)
{
unsigned long flags;
struct edb_node *e, *tmp;
port_id_t sid;
LIST_HEAD(edb_list);
if (DBELL_INACTIVE(vha)) {
/* doorbell list not enabled */
ql_dbg(ql_dbg_edif, vha, 0x09102,
"%s doorbell not enabled\n", __func__);
return;
}
/* grab lock so list doesn't move */
spin_lock_irqsave(&vha->e_dbell.db_lock, flags);
list_for_each_entry_safe(e, tmp, &vha->e_dbell.head, list) {
switch (e->ntype) {
case VND_CMD_AUTH_STATE_NEEDED:
case VND_CMD_AUTH_STATE_SESSION_SHUTDOWN:
sid = e->u.plogi_did;
break;
case VND_CMD_AUTH_STATE_ELS_RCVD:
sid = e->u.els_sid;
break;
case VND_CMD_AUTH_STATE_SAUPDATE_COMPL:
/* app wants to see this */
continue;
default:
ql_log(ql_log_warn, vha, 0x09102,
"%s unknown node type: %x\n", __func__, e->ntype);
sid.b24 = 0;
break;
}
if (sid.b24 == portid.b24) {
ql_dbg(ql_dbg_edif, vha, 0x910f,
"%s free doorbell event : node type = %x %p\n",
__func__, e->ntype, e);
list_del_init(&e->list);
list_add_tail(&e->list, &edb_list);
}
}
spin_unlock_irqrestore(&vha->e_dbell.db_lock, flags);
list_for_each_entry_safe(e, tmp, &edb_list, list) {
qla_edb_node_free(vha, e);
list_del_init(&e->list);
kfree(e);
}
}
/* function called when app is stopping */
void
@@ -1858,7 +1867,7 @@ qla_edb_stop(scsi_qla_host_t *vha)
unsigned long flags;
struct edb_node *node, *q;
if (vha->e_dbell.db_flags != EDB_ACTIVE) {
if (DBELL_INACTIVE(vha)) {
/* doorbell list not enabled */
ql_dbg(ql_dbg_edif, vha, 0x09102,
"%s doorbell not enabled\n", __func__);
@@ -1909,7 +1918,7 @@ qla_edb_node_add(scsi_qla_host_t *vha, struct edb_node *ptr)
{
unsigned long flags;
if (vha->e_dbell.db_flags != EDB_ACTIVE) {
if (DBELL_INACTIVE(vha)) {
/* doorbell list not enabled */
ql_dbg(ql_dbg_edif, vha, 0x09102,
"%s doorbell not enabled\n", __func__);
@@ -1940,7 +1949,7 @@ qla_edb_eventcreate(scsi_qla_host_t *vha, uint32_t dbtype,
return;
}
if (vha->e_dbell.db_flags != EDB_ACTIVE) {
if (DBELL_INACTIVE(vha)) {
if (fcport)
fcport->edif.auth_state = dbtype;
/* doorbell list not enabled */
@@ -2035,7 +2044,7 @@ qla_edif_timer(scsi_qla_host_t *vha)
struct qla_hw_data *ha = vha->hw;
if (!vha->vp_idx && N2N_TOPO(ha) && ha->flags.n2n_fw_acc_sec) {
if (vha->e_dbell.db_flags != EDB_ACTIVE &&
if (DBELL_INACTIVE(vha) &&
ha->edif_post_stop_cnt_down) {
ha->edif_post_stop_cnt_down--;
@@ -2073,7 +2082,7 @@ edif_doorbell_show(struct device *dev, struct device_attribute *attr,
sz = 256;
/* stop new threads from waiting if we're not init'd */
if (vha->e_dbell.db_flags != EDB_ACTIVE) {
if (DBELL_INACTIVE(vha)) {
ql_dbg(ql_dbg_edif + ql_dbg_verbose, vha, 0x09122,
"%s error - edif db not enabled\n", __func__);
return 0;
@@ -2346,6 +2355,7 @@ void qla24xx_auth_els(scsi_qla_host_t *vha, void **pkt, struct rsp_que **rsp)
a.tx_addr = vha->hw->elsrej.cdma;
a.vp_idx = vha->vp_idx;
a.control_flags = EPD_ELS_RJT;
a.ox_id = le16_to_cpu(p->ox_id);
sid = p->s_id[0] | (p->s_id[1] << 8) | (p->s_id[2] << 16);
@@ -2357,7 +2367,7 @@ void qla24xx_auth_els(scsi_qla_host_t *vha, void **pkt, struct rsp_que **rsp)
return;
}
if (totlen > MAX_PAYLOAD) {
if (totlen > ELS_MAX_PAYLOAD) {
ql_dbg(ql_dbg_edif, vha, 0x0910d,
"%s WARNING: verbose ELS frame received (totlen=%x)\n",
__func__, totlen);
@@ -2387,7 +2397,6 @@ void qla24xx_auth_els(scsi_qla_host_t *vha, void **pkt, struct rsp_que **rsp)
purex = &ptr->u.purexinfo;
purex->pur_info.pur_sid = a.did;
purex->pur_info.pur_pend = 0;
purex->pur_info.pur_bytes_rcvd = totlen;
purex->pur_info.pur_rx_xchg_address = le32_to_cpu(p->rx_xchg_addr);
purex->pur_info.pur_nphdl = le16_to_cpu(p->nport_handle);
@@ -2396,6 +2405,8 @@ void qla24xx_auth_els(scsi_qla_host_t *vha, void **pkt, struct rsp_que **rsp)
purex->pur_info.pur_did.b.al_pa = p->d_id[0];
purex->pur_info.vp_idx = p->vp_idx;
a.sid = purex->pur_info.pur_did;
rc = __qla_copy_purex_to_buffer(vha, pkt, rsp, purex->msgp,
purex->msgp_len);
if (rc) {
@@ -2419,7 +2430,7 @@ void qla24xx_auth_els(scsi_qla_host_t *vha, void **pkt, struct rsp_que **rsp)
fcport = qla2x00_find_fcport_by_pid(host, &purex->pur_info.pur_sid);
if (host->e_dbell.db_flags != EDB_ACTIVE ||
if (DBELL_INACTIVE(vha) ||
(fcport && EDIF_SESSION_DOWN(fcport))) {
ql_dbg(ql_dbg_edif, host, 0x0910c, "%s e_dbell.db_flags =%x %06x\n",
__func__, host->e_dbell.db_flags,
@@ -2436,7 +2447,7 @@ void qla24xx_auth_els(scsi_qla_host_t *vha, void **pkt, struct rsp_que **rsp)
ql_dbg(ql_dbg_edif, host, 0x0910c,
"%s COMPLETE purex->pur_info.pur_bytes_rcvd =%xh s:%06x -> d:%06x xchg=%xh\n",
__func__, purex->pur_info.pur_bytes_rcvd, purex->pur_info.pur_sid.b24,
purex->pur_info.pur_did.b24, p->rx_xchg_addr);
purex->pur_info.pur_did.b24, purex->pur_info.pur_rx_xchg_address);
qla_edb_eventcreate(host, VND_CMD_AUTH_STATE_ELS_RCVD, sid, 0, NULL);
}
@@ -3139,18 +3150,14 @@ static uint16_t qla_edif_sadb_get_sa_index(fc_port_t *fcport,
/* release any sadb entries -- only done at teardown */
void qla_edif_sadb_release(struct qla_hw_data *ha)
{
struct list_head *pos;
struct list_head *tmp;
struct edif_sa_index_entry *entry;
struct edif_sa_index_entry *entry, *tmp;
list_for_each_safe(pos, tmp, &ha->sadb_rx_index_list) {
entry = list_entry(pos, struct edif_sa_index_entry, next);
list_for_each_entry_safe(entry, tmp, &ha->sadb_rx_index_list, next) {
list_del(&entry->next);
kfree(entry);
}
list_for_each_safe(pos, tmp, &ha->sadb_tx_index_list) {
entry = list_entry(pos, struct edif_sa_index_entry, next);
list_for_each_entry_safe(entry, tmp, &ha->sadb_tx_index_list, next) {
list_del(&entry->next);
kfree(entry);
}
@@ -3449,7 +3456,7 @@ done:
void qla_edif_sess_down(struct scsi_qla_host *vha, struct fc_port *sess)
{
if (sess->edif.app_sess_online && vha->e_dbell.db_flags & EDB_ACTIVE) {
if (sess->edif.app_sess_online && DBELL_ACTIVE(vha)) {
ql_dbg(ql_dbg_disc, vha, 0xf09c,
"%s: sess %8phN send port_offline event\n",
__func__, sess->port_name);
@@ -3459,3 +3466,12 @@ void qla_edif_sess_down(struct scsi_qla_host *vha, struct fc_port *sess)
qla2x00_post_aen_work(vha, FCH_EVT_PORT_OFFLINE, sess->d_id.b24);
}
}
void qla_edif_clear_appdata(struct scsi_qla_host *vha, struct fc_port *fcport)
{
if (!(fcport->flags & FCF_FCSP_DEVICE))
return;
qla_edb_clear(vha, fcport->d_id);
qla_enode_clear(vha, fcport->d_id);
}

View File

@@ -41,9 +41,12 @@ struct pur_core {
};
enum db_flags_t {
EDB_ACTIVE = 0x1,
EDB_ACTIVE = BIT_0,
};
#define DBELL_ACTIVE(_v) (_v->e_dbell.db_flags & EDB_ACTIVE)
#define DBELL_INACTIVE(_v) (!(_v->e_dbell.db_flags & EDB_ACTIVE))
struct edif_dbell {
enum db_flags_t db_flags;
spinlock_t db_lock;
@@ -93,7 +96,6 @@ struct sa_update_28xx {
};
#define NUM_ENTRIES 256
#define MAX_PAYLOAD 1024
#define PUR_GET 1
struct dinfo {
@@ -102,7 +104,6 @@ struct dinfo {
};
struct pur_ninfo {
unsigned int pur_pend:1;
port_id_t pur_sid;
port_id_t pur_did;
uint8_t vp_idx;
@@ -128,9 +129,15 @@ struct enode {
} u;
};
#define RX_ELS_SIZE (roundup(sizeof(struct enode) + ELS_MAX_PAYLOAD, SMP_CACHE_BYTES))
#define EDIF_SESSION_DOWN(_s) \
(qla_ini_mode_enabled(_s->vha) && (_s->disc_state == DSC_DELETE_PEND || \
_s->disc_state == DSC_DELETED || \
!_s->edif.app_sess_online))
#define EDIF_NEGOTIATION_PENDING(_fcport) \
(DBELL_ACTIVE(_fcport->vha) && \
(_fcport->disc_state == DSC_LOGIN_AUTH_PEND))
#endif /* __QLA_EDIF_H */

View File

@@ -8,7 +8,7 @@
#define __QLA_EDIF_BSG_H
/* BSG Vendor specific commands */
#define ELS_MAX_PAYLOAD 1024
#define ELS_MAX_PAYLOAD 2112
#ifndef WWN_SIZE
#define WWN_SIZE 8
#endif

View File

@@ -142,6 +142,8 @@ void qlt_chk_edif_rx_sa_delete_pending(scsi_qla_host_t *vha, fc_port_t *fcport,
void qla2x00_release_all_sadb(struct scsi_qla_host *vha, struct fc_port *fcport);
int qla_edif_process_els(scsi_qla_host_t *vha, struct bsg_job *bsgjob);
void qla_edif_sess_down(struct scsi_qla_host *vha, struct fc_port *sess);
void qla_edif_clear_appdata(struct scsi_qla_host *vha,
struct fc_port *fcport);
const char *sc_to_str(uint16_t cmd);
/*
@@ -171,7 +173,6 @@ extern int ql2xasynctmfenable;
extern int ql2xgffidenable;
extern int ql2xenabledif;
extern int ql2xenablehba_err_chk;
extern int ql2xtargetreset;
extern int ql2xdontresethba;
extern uint64_t ql2xmaxlun;
extern int ql2xmdcapmask;
@@ -818,7 +819,6 @@ extern void qlafx00_abort_iocb(srb_t *, struct abort_iocb_entry_fx00 *);
extern void qlafx00_fxdisc_iocb(srb_t *, struct fxdisc_entry_fx00 *);
extern void qlafx00_timer_routine(scsi_qla_host_t *);
extern int qlafx00_rescan_isp(scsi_qla_host_t *);
extern int qlafx00_loop_reset(scsi_qla_host_t *vha);
/* qla82xx related functions */

View File

@@ -330,12 +330,9 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
lio->u.logio.flags |= SRB_LOGIN_PRLI_ONLY;
} else {
if (vha->hw->flags.edif_enabled &&
vha->e_dbell.db_flags & EDB_ACTIVE) {
DBELL_ACTIVE(vha)) {
lio->u.logio.flags |=
(SRB_LOGIN_FCSP | SRB_LOGIN_SKIP_PRLI);
ql_dbg(ql_dbg_disc, vha, 0x2072,
"Async-login: w/ FCSP %8phC hdl=%x, loopid=%x portid=%06x\n",
fcport->port_name, sp->handle, fcport->loop_id, fcport->d_id.b24);
} else {
lio->u.logio.flags |= SRB_LOGIN_COND_PLOGI;
}
@@ -344,12 +341,14 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
if (NVME_TARGET(vha->hw, fcport))
lio->u.logio.flags |= SRB_LOGIN_SKIP_PRLI;
ql_dbg(ql_dbg_disc, vha, 0x2072,
"Async-login - %8phC hdl=%x, loopid=%x portid=%06x retries=%d.\n",
fcport->port_name, sp->handle, fcport->loop_id,
fcport->d_id.b24, fcport->login_retry);
rval = qla2x00_start_sp(sp);
ql_dbg(ql_dbg_disc, vha, 0x2072,
"Async-login - %8phC hdl=%x, loopid=%x portid=%06x retries=%d %s.\n",
fcport->port_name, sp->handle, fcport->loop_id,
fcport->d_id.b24, fcport->login_retry,
lio->u.logio.flags & SRB_LOGIN_FCSP ? "FCSP" : "");
if (rval != QLA_SUCCESS) {
fcport->flags |= FCF_LOGIN_NEEDED;
set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
@@ -862,7 +861,7 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha,
break;
case DSC_LS_PLOGI_COMP:
if (vha->hw->flags.edif_enabled &&
vha->e_dbell.db_flags & EDB_ACTIVE) {
DBELL_ACTIVE(vha)) {
/* check to see if App support secure or not */
qla24xx_post_gpdb_work(vha, fcport, 0);
break;
@@ -987,8 +986,6 @@ static void qla24xx_async_gnl_sp_done(srb_t *sp, int res)
sp->name, res, sp->u.iocb_cmd.u.mbx.in_mb[1],
sp->u.iocb_cmd.u.mbx.in_mb[2]);
if (res == QLA_FUNCTION_TIMEOUT)
return;
sp->fcport->flags &= ~(FCF_ASYNC_SENT|FCF_ASYNC_ACTIVE);
memset(&ea, 0, sizeof(ea));
@@ -1026,8 +1023,8 @@ static void qla24xx_async_gnl_sp_done(srb_t *sp, int res)
spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
list_for_each_entry_safe(fcport, tf, &h, gnl_entry) {
list_del_init(&fcport->gnl_entry);
spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
list_del_init(&fcport->gnl_entry);
fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
ea.fcport = fcport;
@@ -1454,7 +1451,7 @@ static int qla_chk_secure_login(scsi_qla_host_t *vha, fc_port_t *fcport,
qla2x00_post_aen_work(vha, FCH_EVT_PORT_ONLINE,
fcport->d_id.b24);
if (vha->e_dbell.db_flags == EDB_ACTIVE) {
if (DBELL_ACTIVE(vha)) {
ql_dbg(ql_dbg_disc, vha, 0x20ef,
"%s %d %8phC EDIF: post DB_AUTH: AUTH needed\n",
__func__, __LINE__, fcport->port_name);
@@ -1786,16 +1783,72 @@ void qla2x00_handle_rscn(scsi_qla_host_t *vha, struct event_arg *ea)
fc_port_t *fcport;
unsigned long flags;
fcport = qla2x00_find_fcport_by_nportid(vha, &ea->id, 1);
if (fcport) {
if (fcport->flags & FCF_FCP2_DEVICE) {
ql_dbg(ql_dbg_disc, vha, 0x2115,
"Delaying session delete for FCP2 portid=%06x %8phC ",
fcport->d_id.b24, fcport->port_name);
return;
switch (ea->id.b.rsvd_1) {
case RSCN_PORT_ADDR:
fcport = qla2x00_find_fcport_by_nportid(vha, &ea->id, 1);
if (fcport) {
if (fcport->flags & FCF_FCP2_DEVICE) {
ql_dbg(ql_dbg_disc, vha, 0x2115,
"Delaying session delete for FCP2 portid=%06x %8phC ",
fcport->d_id.b24, fcport->port_name);
return;
}
if (vha->hw->flags.edif_enabled && DBELL_ACTIVE(vha)) {
/*
* On ipsec start by remote port, Target port
* may use RSCN to trigger initiator to
* relogin. If driver is already in the
* process of a relogin, then ignore the RSCN
* and allow the current relogin to continue.
* This reduces thrashing of the connection.
*/
if (atomic_read(&fcport->state) == FCS_ONLINE) {
/*
* If state = online, then set scan_needed=1 to do relogin.
* Otherwise we're already in the middle of a relogin
*/
fcport->scan_needed = 1;
fcport->rscn_gen++;
}
} else {
fcport->scan_needed = 1;
fcport->rscn_gen++;
}
}
fcport->scan_needed = 1;
fcport->rscn_gen++;
break;
case RSCN_AREA_ADDR:
list_for_each_entry(fcport, &vha->vp_fcports, list) {
if (fcport->flags & FCF_FCP2_DEVICE)
continue;
if ((ea->id.b24 & 0xffff00) == (fcport->d_id.b24 & 0xffff00)) {
fcport->scan_needed = 1;
fcport->rscn_gen++;
}
}
break;
case RSCN_DOM_ADDR:
list_for_each_entry(fcport, &vha->vp_fcports, list) {
if (fcport->flags & FCF_FCP2_DEVICE)
continue;
if ((ea->id.b24 & 0xff0000) == (fcport->d_id.b24 & 0xff0000)) {
fcport->scan_needed = 1;
fcport->rscn_gen++;
}
}
break;
case RSCN_FAB_ADDR:
default:
list_for_each_entry(fcport, &vha->vp_fcports, list) {
if (fcport->flags & FCF_FCP2_DEVICE)
continue;
fcport->scan_needed = 1;
fcport->rscn_gen++;
}
break;
}
spin_lock_irqsave(&vha->work_lock, flags);
@@ -4187,7 +4240,7 @@ qla24xx_update_fw_options(scsi_qla_host_t *vha)
* fw shal not send PRLI after PLOGI Acc
*/
if (ha->flags.edif_enabled &&
vha->e_dbell.db_flags & EDB_ACTIVE) {
DBELL_ACTIVE(vha)) {
ha->fw_options[3] |= BIT_15;
ha->flags.n2n_fw_acc_sec = 1;
} else {
@@ -4433,6 +4486,10 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
(ha->flags.fawwpn_enabled) ? "enabled" : "disabled");
}
/* ELS pass through payload is limit by frame size. */
if (ha->flags.edif_enabled)
mid_init_cb->init_cb.frame_payload_size = cpu_to_le16(ELS_MAX_PAYLOAD);
rval = qla2x00_init_firmware(vha, ha->init_cb_size);
next_check:
if (rval) {
@@ -5339,8 +5396,7 @@ qla2x00_configure_loop(scsi_qla_host_t *vha)
* use link up to wake up app to get ready for
* authentication.
*/
if (ha->flags.edif_enabled &&
!(vha->e_dbell.db_flags & EDB_ACTIVE))
if (ha->flags.edif_enabled && DBELL_INACTIVE(vha))
qla2x00_post_aen_work(vha, FCH_EVT_LINKUP,
ha->link_data_rate);
@@ -5833,6 +5889,10 @@ void qla_register_fcport_fn(struct work_struct *work)
qla2x00_update_fcport(fcport->vha, fcport);
ql_dbg(ql_dbg_disc, fcport->vha, 0x911e,
"%s rscn gen %d/%d next DS %d\n", __func__,
rscn_gen, fcport->rscn_gen, fcport->next_disc_state);
if (rscn_gen != fcport->rscn_gen) {
/* RSCN(s) came in while registration */
switch (fcport->next_disc_state) {

View File

@@ -3034,8 +3034,7 @@ qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode,
elsio->u.els_plogi.els_cmd = els_opcode;
elsio->u.els_plogi.els_plogi_pyld->opcode = els_opcode;
if (els_opcode == ELS_DCMD_PLOGI && vha->hw->flags.edif_enabled &&
vha->e_dbell.db_flags & EDB_ACTIVE) {
if (els_opcode == ELS_DCMD_PLOGI && DBELL_ACTIVE(vha)) {
struct fc_els_flogi *p = ptr;
p->fl_csp.sp_features |= cpu_to_be16(FC_SP_FT_SEC);

View File

@@ -2233,6 +2233,10 @@ qla24xx_els_ct_entry(scsi_qla_host_t *v, struct req_que *req,
}
} else if (comp_status == CS_PORT_LOGGED_OUT) {
ql_dbg(ql_dbg_disc, vha, 0x911e,
"%s %d schedule session deletion\n",
__func__, __LINE__);
els->u.els_plogi.len = 0;
res = DID_IMM_RETRY << 16;
qlt_schedule_sess_for_deletion(sp->fcport);

View File

@@ -738,29 +738,6 @@ qlafx00_lun_reset(fc_port_t *fcport, uint64_t l, int tag)
return qla2x00_async_tm_cmd(fcport, TCF_LUN_RESET, l, tag);
}
int
qlafx00_loop_reset(scsi_qla_host_t *vha)
{
int ret;
struct fc_port *fcport;
struct qla_hw_data *ha = vha->hw;
if (ql2xtargetreset) {
list_for_each_entry(fcport, &vha->vp_fcports, list) {
if (fcport->port_type != FCT_TARGET)
continue;
ret = ha->isp_ops->target_reset(fcport, 0, 0);
if (ret != QLA_SUCCESS) {
ql_dbg(ql_dbg_taskm, vha, 0x803d,
"Bus Reset failed: Reset=%d "
"d_id=%x.\n", ret, fcport->d_id.b24);
}
}
}
return QLA_SUCCESS;
}
int
qlafx00_iospace_config(struct qla_hw_data *ha)
{

View File

@@ -202,12 +202,6 @@ MODULE_PARM_DESC(ql2xdbwr,
" 0 -- Regular doorbell.\n"
" 1 -- CAMRAM doorbell (faster).\n");
int ql2xtargetreset = 1;
module_param(ql2xtargetreset, int, S_IRUGO);
MODULE_PARM_DESC(ql2xtargetreset,
"Enable target reset."
"Default is 1 - use hw defaults.");
int ql2xgffidenable;
module_param(ql2xgffidenable, int, S_IRUGO);
MODULE_PARM_DESC(ql2xgffidenable,
@@ -1695,27 +1689,10 @@ int
qla2x00_loop_reset(scsi_qla_host_t *vha)
{
int ret;
struct fc_port *fcport;
struct qla_hw_data *ha = vha->hw;
if (IS_QLAFX00(ha)) {
return qlafx00_loop_reset(vha);
}
if (ql2xtargetreset == 1 && ha->flags.enable_target_reset) {
list_for_each_entry(fcport, &vha->vp_fcports, list) {
if (fcport->port_type != FCT_TARGET)
continue;
ret = ha->isp_ops->target_reset(fcport, 0, 0);
if (ret != QLA_SUCCESS) {
ql_dbg(ql_dbg_taskm, vha, 0x802c,
"Bus Reset failed: Reset=%d "
"d_id=%x.\n", ret, fcport->d_id.b24);
}
}
}
if (IS_QLAFX00(ha))
return QLA_SUCCESS;
if (ha->flags.enable_lip_full_login && !IS_CNA_CAPABLE(ha)) {
atomic_set(&vha->loop_state, LOOP_DOWN);
@@ -3908,13 +3885,13 @@ qla2x00_remove_one(struct pci_dev *pdev)
static inline void
qla24xx_free_purex_list(struct purex_list *list)
{
struct list_head *item, *next;
struct purex_item *item, *next;
ulong flags;
spin_lock_irqsave(&list->lock, flags);
list_for_each_safe(item, next, &list->head) {
list_del(item);
kfree(list_entry(item, struct purex_item, list));
list_for_each_entry_safe(item, next, &list->head, list) {
list_del(&item->list);
kfree(item);
}
spin_unlock_irqrestore(&list->lock, flags);
}
@@ -4375,7 +4352,7 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
/* allocate the purex dma pool */
ha->purex_dma_pool = dma_pool_create(name, &ha->pdev->dev,
MAX_PAYLOAD, 8, 0);
ELS_MAX_PAYLOAD, 8, 0);
if (!ha->purex_dma_pool) {
ql_dbg_pci(ql_dbg_init, ha->pdev, 0x011b,

View File

@@ -1003,6 +1003,7 @@ void qlt_free_session_done(struct work_struct *work)
"%s bypassing release_all_sadb\n",
__func__);
}
qla_edif_clear_appdata(vha, sess);
qla_edif_sess_down(vha, sess);
}
qla2x00_mark_device_lost(vha, sess, 0);
@@ -4812,7 +4813,7 @@ static int qlt_handle_login(struct scsi_qla_host *vha,
}
if (vha->hw->flags.edif_enabled) {
if (!(vha->e_dbell.db_flags & EDB_ACTIVE)) {
if (DBELL_INACTIVE(vha)) {
ql_dbg(ql_dbg_disc, vha, 0xffff,
"%s %d Term INOT due to app not started lid=%d, NportID %06X ",
__func__, __LINE__, loop_id, port_id.b24);

View File

@@ -6,9 +6,9 @@
/*
* Driver version
*/
#define QLA2XXX_VERSION "10.02.07.100-k"
#define QLA2XXX_VERSION "10.02.07.200-k"
#define QLA_DRIVER_MAJOR_VER 10
#define QLA_DRIVER_MINOR_VER 2
#define QLA_DRIVER_PATCH_VER 7
#define QLA_DRIVER_BETA_VER 100
#define QLA_DRIVER_BETA_VER 200

View File

@@ -4259,6 +4259,8 @@ static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
mk_sense_invalid_opcode(scp);
return check_condition_result;
}
if (vnum == 0)
return 0; /* not an error */
a_num = is_bytchk3 ? 1 : vnum;
/* Treat following check like one for read (i.e. no write) access */
ret = check_device_access_params(scp, lba, a_num, false);
@@ -4322,6 +4324,8 @@ static int resp_report_zones(struct scsi_cmnd *scp,
}
zs_lba = get_unaligned_be64(cmd + 2);
alloc_len = get_unaligned_be32(cmd + 10);
if (alloc_len == 0)
return 0; /* not an error */
rep_opts = cmd[14] & 0x3f;
partial = cmd[14] & 0x80;

View File

@@ -133,6 +133,23 @@ static bool scsi_eh_should_retry_cmd(struct scsi_cmnd *cmd)
return true;
}
static void scsi_eh_complete_abort(struct scsi_cmnd *scmd, struct Scsi_Host *shost)
{
unsigned long flags;
spin_lock_irqsave(shost->host_lock, flags);
list_del_init(&scmd->eh_entry);
/*
* If the abort succeeds, and there is no further
* EH action, clear the ->last_reset time.
*/
if (list_empty(&shost->eh_abort_list) &&
list_empty(&shost->eh_cmd_q))
if (shost->eh_deadline != -1)
shost->last_reset = 0;
spin_unlock_irqrestore(shost->host_lock, flags);
}
/**
* scmd_eh_abort_handler - Handle command aborts
* @work: command to be aborted.
@@ -150,6 +167,7 @@ scmd_eh_abort_handler(struct work_struct *work)
container_of(work, struct scsi_cmnd, abort_work.work);
struct scsi_device *sdev = scmd->device;
enum scsi_disposition rtn;
unsigned long flags;
if (scsi_host_eh_past_deadline(sdev->host)) {
SCSI_LOG_ERROR_RECOVERY(3,
@@ -173,12 +191,14 @@ scmd_eh_abort_handler(struct work_struct *work)
SCSI_LOG_ERROR_RECOVERY(3,
scmd_printk(KERN_WARNING, scmd,
"retry aborted command\n"));
scsi_eh_complete_abort(scmd, sdev->host);
scsi_queue_insert(scmd, SCSI_MLQUEUE_EH_RETRY);
return;
} else {
SCSI_LOG_ERROR_RECOVERY(3,
scmd_printk(KERN_WARNING, scmd,
"finish aborted command\n"));
scsi_eh_complete_abort(scmd, sdev->host);
scsi_finish_command(scmd);
return;
}
@@ -191,6 +211,9 @@ scmd_eh_abort_handler(struct work_struct *work)
}
}
spin_lock_irqsave(sdev->host->host_lock, flags);
list_del_init(&scmd->eh_entry);
spin_unlock_irqrestore(sdev->host->host_lock, flags);
scsi_eh_scmd_add(scmd);
}
@@ -221,6 +244,8 @@ scsi_abort_command(struct scsi_cmnd *scmd)
spin_lock_irqsave(shost->host_lock, flags);
if (shost->eh_deadline != -1 && !shost->last_reset)
shost->last_reset = jiffies;
BUG_ON(!list_empty(&scmd->eh_entry));
list_add_tail(&scmd->eh_entry, &shost->eh_abort_list);
spin_unlock_irqrestore(shost->host_lock, flags);
scmd->eh_eflags |= SCSI_EH_ABORT_SCHEDULED;

View File

@@ -347,6 +347,8 @@ static int scsi_fill_sghdr_rq(struct scsi_device *sdev, struct request *rq,
{
struct scsi_request *req = scsi_req(rq);
if (hdr->cmd_len < 6)
return -EMSGSIZE;
if (copy_from_user(req->cmd, hdr->cmdp, hdr->cmd_len))
return -EFAULT;
if (!scsi_cmd_allowed(req->cmd, mode))

View File

@@ -1153,6 +1153,7 @@ void scsi_init_command(struct scsi_device *dev, struct scsi_cmnd *cmd)
cmd->sense_buffer = buf;
cmd->prot_sdb = prot;
cmd->flags = flags;
INIT_LIST_HEAD(&cmd->eh_entry);
INIT_DELAYED_WORK(&cmd->abort_work, scmd_eh_abort_handler);
cmd->jiffies_at_alloc = jiffies_at_alloc;
cmd->retries = retries;
@@ -1184,8 +1185,6 @@ static blk_status_t scsi_setup_scsi_cmnd(struct scsi_device *sdev,
}
cmd->cmd_len = scsi_req(req)->cmd_len;
if (cmd->cmd_len == 0)
cmd->cmd_len = scsi_command_size(cmd->cmnd);
cmd->cmnd = scsi_req(req)->cmd;
cmd->transfersize = blk_rq_bytes(req);
cmd->allowed = scsi_req(req)->retries;

View File

@@ -1383,6 +1383,7 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev)
* We're treating error on bsg register as non-fatal, so
* pretend nothing went wrong.
*/
error = PTR_ERR(sdev->bsg_dev);
sdev_printk(KERN_INFO, sdev,
"Failed to register bsg queue, errno=%d\n",
error);
@@ -1580,7 +1581,6 @@ static struct device_type scsi_dev_type = {
void scsi_sysfs_device_initialize(struct scsi_device *sdev)
{
int i, j = 0;
unsigned long flags;
struct Scsi_Host *shost = sdev->host;
struct scsi_host_template *hostt = shost->hostt;
@@ -1592,15 +1592,7 @@ void scsi_sysfs_device_initialize(struct scsi_device *sdev)
scsi_enable_async_suspend(&sdev->sdev_gendev);
dev_set_name(&sdev->sdev_gendev, "%d:%d:%d:%llu",
sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
sdev->gendev_attr_groups[j++] = &scsi_sdev_attr_group;
if (hostt->sdev_groups) {
for (i = 0; hostt->sdev_groups[i] &&
j < ARRAY_SIZE(sdev->gendev_attr_groups);
i++, j++) {
sdev->gendev_attr_groups[j] = hostt->sdev_groups[i];
}
}
WARN_ON_ONCE(j >= ARRAY_SIZE(sdev->gendev_attr_groups));
sdev->sdev_gendev.groups = hostt->sdev_groups;
device_initialize(&sdev->sdev_dev);
sdev->sdev_dev.parent = get_device(&sdev->sdev_gendev);

View File

@@ -693,7 +693,6 @@ static int sr_probe(struct device *dev)
cd->device = sdev;
cd->disk = disk;
cd->driver = &sr_template;
cd->disk = disk;
cd->capacity = 0x1fffff;
cd->device->changed = 1; /* force recheck CD type */
cd->media_present = 1;

View File

@@ -8,6 +8,18 @@
static struct dentry *ufs_debugfs_root;
struct ufs_debugfs_attr {
const char *name;
mode_t mode;
const struct file_operations *fops;
};
/* @file corresponds to a debugfs attribute in directory hba->debugfs_root. */
static inline struct ufs_hba *hba_from_file(const struct file *file)
{
return d_inode(file->f_path.dentry->d_parent)->i_private;
}
void __init ufs_debugfs_init(void)
{
ufs_debugfs_root = debugfs_create_dir("ufshcd", NULL);
@@ -20,7 +32,7 @@ void ufs_debugfs_exit(void)
static int ufs_debugfs_stats_show(struct seq_file *s, void *data)
{
struct ufs_hba *hba = s->private;
struct ufs_hba *hba = hba_from_file(s->file);
struct ufs_event_hist *e = hba->ufs_stats.event;
#define PRT(fmt, typ) \
@@ -126,13 +138,93 @@ static void ufs_debugfs_restart_ee(struct work_struct *work)
ufs_debugfs_put_user_access(hba);
}
static int ufs_saved_err_show(struct seq_file *s, void *data)
{
struct ufs_debugfs_attr *attr = s->private;
struct ufs_hba *hba = hba_from_file(s->file);
const int *p;
if (strcmp(attr->name, "saved_err") == 0) {
p = &hba->saved_err;
} else if (strcmp(attr->name, "saved_uic_err") == 0) {
p = &hba->saved_uic_err;
} else {
return -ENOENT;
}
seq_printf(s, "%d\n", *p);
return 0;
}
static ssize_t ufs_saved_err_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
struct ufs_debugfs_attr *attr = file->f_inode->i_private;
struct ufs_hba *hba = hba_from_file(file);
char val_str[16] = { };
int val, ret;
if (count > sizeof(val_str))
return -EINVAL;
if (copy_from_user(val_str, buf, count))
return -EFAULT;
ret = kstrtoint(val_str, 0, &val);
if (ret < 0)
return ret;
spin_lock_irq(hba->host->host_lock);
if (strcmp(attr->name, "saved_err") == 0) {
hba->saved_err = val;
} else if (strcmp(attr->name, "saved_uic_err") == 0) {
hba->saved_uic_err = val;
} else {
ret = -ENOENT;
}
if (ret == 0)
ufshcd_schedule_eh_work(hba);
spin_unlock_irq(hba->host->host_lock);
return ret < 0 ? ret : count;
}
static int ufs_saved_err_open(struct inode *inode, struct file *file)
{
return single_open(file, ufs_saved_err_show, inode->i_private);
}
static const struct file_operations ufs_saved_err_fops = {
.owner = THIS_MODULE,
.open = ufs_saved_err_open,
.read = seq_read,
.write = ufs_saved_err_write,
.llseek = seq_lseek,
.release = single_release,
};
static const struct ufs_debugfs_attr ufs_attrs[] = {
{ "stats", 0400, &ufs_debugfs_stats_fops },
{ "saved_err", 0600, &ufs_saved_err_fops },
{ "saved_uic_err", 0600, &ufs_saved_err_fops },
{ }
};
void ufs_debugfs_hba_init(struct ufs_hba *hba)
{
const struct ufs_debugfs_attr *attr;
struct dentry *root;
/* Set default exception event rate limit period to 20ms */
hba->debugfs_ee_rate_limit_ms = 20;
INIT_DELAYED_WORK(&hba->debugfs_ee_work, ufs_debugfs_restart_ee);
hba->debugfs_root = debugfs_create_dir(dev_name(hba->dev), ufs_debugfs_root);
debugfs_create_file("stats", 0400, hba->debugfs_root, hba, &ufs_debugfs_stats_fops);
root = debugfs_create_dir(dev_name(hba->dev), ufs_debugfs_root);
if (IS_ERR_OR_NULL(root))
return;
hba->debugfs_root = root;
d_inode(root)->i_private = hba;
for (attr = ufs_attrs; attr->name; attr++)
debugfs_create_file(attr->name, attr->mode, root, (void *)attr,
attr->fops);
debugfs_create_file("exception_event_mask", 0600, hba->debugfs_root,
hba, &ee_usr_mask_fops);
debugfs_create_u32("exception_event_rate_limit_ms", 0600, hba->debugfs_root,

View File

@@ -12,8 +12,10 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/mfd/syscon.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include "ufshcd.h"
#include "ufshcd-pltfrm.h"
@@ -48,10 +50,11 @@
#define HCI_ERR_EN_T_LAYER 0x84
#define HCI_ERR_EN_DME_LAYER 0x88
#define HCI_CLKSTOP_CTRL 0xB0
#define REFCLKOUT_STOP BIT(4)
#define REFCLK_STOP BIT(2)
#define UNIPRO_MCLK_STOP BIT(1)
#define UNIPRO_PCLK_STOP BIT(0)
#define CLK_STOP_MASK (REFCLK_STOP |\
#define CLK_STOP_MASK (REFCLKOUT_STOP | REFCLK_STOP |\
UNIPRO_MCLK_STOP |\
UNIPRO_PCLK_STOP)
#define HCI_MISC 0xB4
@@ -74,6 +77,52 @@
UIC_TRANSPORT_NO_CONNECTION_RX |\
UIC_TRANSPORT_BAD_TC)
/* FSYS UFS Shareability */
#define UFS_WR_SHARABLE BIT(2)
#define UFS_RD_SHARABLE BIT(1)
#define UFS_SHARABLE (UFS_WR_SHARABLE | UFS_RD_SHARABLE)
#define UFS_SHAREABILITY_OFFSET 0x710
/* Multi-host registers */
#define MHCTRL 0xC4
#define MHCTRL_EN_VH_MASK (0xE)
#define MHCTRL_EN_VH(vh) (vh << 1)
#define PH2VH_MBOX 0xD8
#define MH_MSG_MASK (0xFF)
#define MH_MSG(id, msg) ((id << 8) | (msg & 0xFF))
#define MH_MSG_PH_READY 0x1
#define MH_MSG_VH_READY 0x2
#define ALLOW_INQUIRY BIT(25)
#define ALLOW_MODE_SELECT BIT(24)
#define ALLOW_MODE_SENSE BIT(23)
#define ALLOW_PRE_FETCH GENMASK(22, 21)
#define ALLOW_READ_CMD_ALL GENMASK(20, 18) /* read_6/10/16 */
#define ALLOW_READ_BUFFER BIT(17)
#define ALLOW_READ_CAPACITY GENMASK(16, 15)
#define ALLOW_REPORT_LUNS BIT(14)
#define ALLOW_REQUEST_SENSE BIT(13)
#define ALLOW_SYNCHRONIZE_CACHE GENMASK(8, 7)
#define ALLOW_TEST_UNIT_READY BIT(6)
#define ALLOW_UNMAP BIT(5)
#define ALLOW_VERIFY BIT(4)
#define ALLOW_WRITE_CMD_ALL GENMASK(3, 1) /* write_6/10/16 */
#define ALLOW_TRANS_VH_DEFAULT (ALLOW_INQUIRY | ALLOW_MODE_SELECT | \
ALLOW_MODE_SENSE | ALLOW_PRE_FETCH | \
ALLOW_READ_CMD_ALL | ALLOW_READ_BUFFER | \
ALLOW_READ_CAPACITY | ALLOW_REPORT_LUNS | \
ALLOW_REQUEST_SENSE | ALLOW_SYNCHRONIZE_CACHE | \
ALLOW_TEST_UNIT_READY | ALLOW_UNMAP | \
ALLOW_VERIFY | ALLOW_WRITE_CMD_ALL)
#define HCI_MH_ALLOWABLE_TRAN_OF_VH 0x30C
#define HCI_MH_IID_IN_TASK_TAG 0X308
#define PH_READY_TIMEOUT_MS (5 * MSEC_PER_SEC)
enum {
UNIPRO_L1_5 = 0,/* PHY Adapter */
UNIPRO_L2, /* Data Link */
@@ -149,6 +198,117 @@ static int exynos7_ufs_drv_init(struct device *dev, struct exynos_ufs *ufs)
return 0;
}
static int exynosauto_ufs_drv_init(struct device *dev, struct exynos_ufs *ufs)
{
struct exynos_ufs_uic_attr *attr = ufs->drv_data->uic_attr;
/* IO Coherency setting */
if (ufs->sysreg) {
return regmap_update_bits(ufs->sysreg,
ufs->shareability_reg_offset,
UFS_SHARABLE, UFS_SHARABLE);
}
attr->tx_dif_p_nsec = 3200000;
return 0;
}
static int exynosauto_ufs_post_hce_enable(struct exynos_ufs *ufs)
{
struct ufs_hba *hba = ufs->hba;
/* Enable Virtual Host #1 */
ufshcd_rmwl(hba, MHCTRL_EN_VH_MASK, MHCTRL_EN_VH(1), MHCTRL);
/* Default VH Transfer permissions */
hci_writel(ufs, ALLOW_TRANS_VH_DEFAULT, HCI_MH_ALLOWABLE_TRAN_OF_VH);
/* IID information is replaced in TASKTAG[7:5] instead of IID in UCD */
hci_writel(ufs, 0x1, HCI_MH_IID_IN_TASK_TAG);
return 0;
}
static int exynosauto_ufs_pre_link(struct exynos_ufs *ufs)
{
struct ufs_hba *hba = ufs->hba;
int i;
u32 tx_line_reset_period, rx_line_reset_period;
rx_line_reset_period = (RX_LINE_RESET_TIME * ufs->mclk_rate) / NSEC_PER_MSEC;
tx_line_reset_period = (TX_LINE_RESET_TIME * ufs->mclk_rate) / NSEC_PER_MSEC;
ufshcd_dme_set(hba, UIC_ARG_MIB(0x200), 0x40);
for_each_ufs_rx_lane(ufs, i) {
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_CLK_PRD, i),
DIV_ROUND_UP(NSEC_PER_SEC, ufs->mclk_rate));
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_CLK_PRD_EN, i), 0x0);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_VALUE2, i),
(rx_line_reset_period >> 16) & 0xFF);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_VALUE1, i),
(rx_line_reset_period >> 8) & 0xFF);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_RX_LINERESET_VALUE0, i),
(rx_line_reset_period) & 0xFF);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x2f, i), 0x79);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x84, i), 0x1);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x25, i), 0xf6);
}
for_each_ufs_tx_lane(ufs, i) {
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_CLK_PRD, i),
DIV_ROUND_UP(NSEC_PER_SEC, ufs->mclk_rate));
/* Not to affect VND_TX_LINERESET_PVALUE to VND_TX_CLK_PRD */
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_CLK_PRD_EN, i),
0x02);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_LINERESET_PVALUE2, i),
(tx_line_reset_period >> 16) & 0xFF);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_LINERESET_PVALUE1, i),
(tx_line_reset_period >> 8) & 0xFF);
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(VND_TX_LINERESET_PVALUE0, i),
(tx_line_reset_period) & 0xFF);
/* TX PWM Gear Capability / PWM_G1_ONLY */
ufshcd_dme_set(hba, UIC_ARG_MIB_SEL(0x04, i), 0x1);
}
ufshcd_dme_set(hba, UIC_ARG_MIB(0x200), 0x0);
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE), 0x0);
ufshcd_dme_set(hba, UIC_ARG_MIB(0xa011), 0x8000);
return 0;
}
static int exynosauto_ufs_pre_pwr_change(struct exynos_ufs *ufs,
struct ufs_pa_layer_attr *pwr)
{
struct ufs_hba *hba = ufs->hba;
/* PACP_PWR_req and delivered to the remote DME */
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA0), 12000);
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA1), 32000);
ufshcd_dme_set(hba, UIC_ARG_MIB(PA_PWRMODEUSERDATA2), 16000);
return 0;
}
static int exynosauto_ufs_post_pwr_change(struct exynos_ufs *ufs,
struct ufs_pa_layer_attr *pwr)
{
struct ufs_hba *hba = ufs->hba;
u32 enabled_vh;
enabled_vh = ufshcd_readl(hba, MHCTRL) & MHCTRL_EN_VH_MASK;
/* Send physical host ready message to virtual hosts */
ufshcd_writel(hba, MH_MSG(enabled_vh, MH_MSG_PH_READY), PH2VH_MBOX);
return 0;
}
static int exynos7_ufs_pre_link(struct exynos_ufs *ufs)
{
struct ufs_hba *hba = ufs->hba;
@@ -793,6 +953,27 @@ static void exynos_ufs_config_intr(struct exynos_ufs *ufs, u32 errs, u8 index)
}
}
static int exynos_ufs_setup_clocks(struct ufs_hba *hba, bool on,
enum ufs_notify_change_status status)
{
struct exynos_ufs *ufs = ufshcd_get_variant(hba);
if (!ufs)
return 0;
if (on && status == PRE_CHANGE) {
if (ufs->opts & EXYNOS_UFS_OPT_BROKEN_AUTO_CLK_CTRL)
exynos_ufs_disable_auto_ctrl_hcc(ufs);
exynos_ufs_ungate_clks(ufs);
} else if (!on && status == POST_CHANGE) {
exynos_ufs_gate_clks(ufs);
if (ufs->opts & EXYNOS_UFS_OPT_BROKEN_AUTO_CLK_CTRL)
exynos_ufs_enable_auto_ctrl_hcc(ufs);
}
return 0;
}
static int exynos_ufs_pre_link(struct ufs_hba *hba)
{
struct exynos_ufs *ufs = ufshcd_get_variant(hba);
@@ -808,8 +989,12 @@ static int exynos_ufs_pre_link(struct ufs_hba *hba)
/* m-phy */
exynos_ufs_phy_init(ufs);
exynos_ufs_config_phy_time_attr(ufs);
exynos_ufs_config_phy_cap_attr(ufs);
if (!(ufs->opts & EXYNOS_UFS_OPT_SKIP_CONFIG_PHY_ATTR)) {
exynos_ufs_config_phy_time_attr(ufs);
exynos_ufs_config_phy_cap_attr(ufs);
}
exynos_ufs_setup_clocks(hba, true, PRE_CHANGE);
if (ufs->drv_data->pre_link)
ufs->drv_data->pre_link(ufs);
@@ -893,17 +1078,10 @@ static int exynos_ufs_post_link(struct ufs_hba *hba)
static int exynos_ufs_parse_dt(struct device *dev, struct exynos_ufs *ufs)
{
struct device_node *np = dev->of_node;
struct exynos_ufs_drv_data *drv_data = &exynos_ufs_drvs;
struct exynos_ufs_uic_attr *attr;
int ret = 0;
while (drv_data->compatible) {
if (of_device_is_compatible(np, drv_data->compatible)) {
ufs->drv_data = drv_data;
break;
}
drv_data++;
}
ufs->drv_data = device_get_match_data(dev);
if (ufs->drv_data && ufs->drv_data->uic_attr) {
attr = ufs->drv_data->uic_attr;
@@ -913,6 +1091,17 @@ static int exynos_ufs_parse_dt(struct device *dev, struct exynos_ufs *ufs)
goto out;
}
ufs->sysreg = syscon_regmap_lookup_by_phandle(np, "samsung,sysreg");
if (IS_ERR(ufs->sysreg))
ufs->sysreg = NULL;
else {
if (of_property_read_u32_index(np, "samsung,sysreg", 1,
&ufs->shareability_reg_offset)) {
dev_warn(dev, "can't get an offset from sysreg. Set to default value\n");
ufs->shareability_reg_offset = UFS_SHAREABILITY_OFFSET;
}
}
ufs->pclk_avail_min = PCLK_AVAIL_MIN;
ufs->pclk_avail_max = PCLK_AVAIL_MAX;
@@ -927,6 +1116,18 @@ out:
return ret;
}
static inline void exynos_ufs_priv_init(struct ufs_hba *hba,
struct exynos_ufs *ufs)
{
ufs->hba = hba;
ufs->opts = ufs->drv_data->opts;
ufs->rx_sel_idx = PA_MAXDATALANES;
if (ufs->opts & EXYNOS_UFS_OPT_BROKEN_RX_SEL_IDX)
ufs->rx_sel_idx = 0;
hba->priv = (void *)ufs;
hba->quirks = ufs->drv_data->quirks;
}
static int exynos_ufs_init(struct ufs_hba *hba)
{
struct device *dev = hba->dev;
@@ -976,13 +1177,8 @@ static int exynos_ufs_init(struct ufs_hba *hba)
if (ret)
goto phy_off;
ufs->hba = hba;
ufs->opts = ufs->drv_data->opts;
ufs->rx_sel_idx = PA_MAXDATALANES;
if (ufs->opts & EXYNOS_UFS_OPT_BROKEN_RX_SEL_IDX)
ufs->rx_sel_idx = 0;
hba->priv = (void *)ufs;
hba->quirks = ufs->drv_data->quirks;
exynos_ufs_priv_init(hba, ufs);
if (ufs->drv_data->drv_init) {
ret = ufs->drv_data->drv_init(dev, ufs);
if (ret) {
@@ -1110,6 +1306,12 @@ static int exynos_ufs_hce_enable_notify(struct ufs_hba *hba,
switch (status) {
case PRE_CHANGE:
if (ufs->drv_data->pre_hce_enable) {
ret = ufs->drv_data->pre_hce_enable(ufs);
if (ret)
return ret;
}
ret = exynos_ufs_host_reset(hba);
if (ret)
return ret;
@@ -1119,6 +1321,10 @@ static int exynos_ufs_hce_enable_notify(struct ufs_hba *hba,
exynos_ufs_calc_pwm_clk_div(ufs);
if (!(ufs->opts & EXYNOS_UFS_OPT_BROKEN_AUTO_CLK_CTRL))
exynos_ufs_enable_auto_ctrl_hcc(ufs);
if (ufs->drv_data->post_hce_enable)
ret = ufs->drv_data->post_hce_enable(ufs);
break;
}
@@ -1202,12 +1408,77 @@ static int exynos_ufs_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
return 0;
}
static int exynosauto_ufs_vh_link_startup_notify(struct ufs_hba *hba,
enum ufs_notify_change_status status)
{
if (status == POST_CHANGE) {
ufshcd_set_link_active(hba);
ufshcd_set_ufs_dev_active(hba);
}
return 0;
}
static int exynosauto_ufs_vh_wait_ph_ready(struct ufs_hba *hba)
{
u32 mbox;
ktime_t start, stop;
start = ktime_get();
stop = ktime_add(start, ms_to_ktime(PH_READY_TIMEOUT_MS));
do {
mbox = ufshcd_readl(hba, PH2VH_MBOX);
/* TODO: Mailbox message protocols between the PH and VHs are
* not implemented yet. This will be supported later
*/
if ((mbox & MH_MSG_MASK) == MH_MSG_PH_READY)
return 0;
usleep_range(40, 50);
} while (ktime_before(ktime_get(), stop));
return -ETIME;
}
static int exynosauto_ufs_vh_init(struct ufs_hba *hba)
{
struct device *dev = hba->dev;
struct platform_device *pdev = to_platform_device(dev);
struct exynos_ufs *ufs;
int ret;
ufs = devm_kzalloc(dev, sizeof(*ufs), GFP_KERNEL);
if (!ufs)
return -ENOMEM;
/* exynos-specific hci */
ufs->reg_hci = devm_platform_ioremap_resource_byname(pdev, "vs_hci");
if (IS_ERR(ufs->reg_hci)) {
dev_err(dev, "cannot ioremap for hci vendor register\n");
return PTR_ERR(ufs->reg_hci);
}
ret = exynosauto_ufs_vh_wait_ph_ready(hba);
if (ret)
return ret;
ufs->drv_data = device_get_match_data(dev);
if (!ufs->drv_data)
return -ENODEV;
exynos_ufs_priv_init(hba, ufs);
return 0;
}
static struct ufs_hba_variant_ops ufs_hba_exynos_ops = {
.name = "exynos_ufs",
.init = exynos_ufs_init,
.hce_enable_notify = exynos_ufs_hce_enable_notify,
.link_startup_notify = exynos_ufs_link_startup_notify,
.pwr_change_notify = exynos_ufs_pwr_change_notify,
.setup_clocks = exynos_ufs_setup_clocks,
.setup_xfer_req = exynos_ufs_specify_nexus_t_xfer_req,
.setup_task_mgmt = exynos_ufs_specify_nexus_t_tm_req,
.hibern8_notify = exynos_ufs_hibern8_notify,
@@ -1215,12 +1486,24 @@ static struct ufs_hba_variant_ops ufs_hba_exynos_ops = {
.resume = exynos_ufs_resume,
};
static struct ufs_hba_variant_ops ufs_hba_exynosauto_vh_ops = {
.name = "exynosauto_ufs_vh",
.init = exynosauto_ufs_vh_init,
.link_startup_notify = exynosauto_ufs_vh_link_startup_notify,
};
static int exynos_ufs_probe(struct platform_device *pdev)
{
int err;
struct device *dev = &pdev->dev;
const struct ufs_hba_variant_ops *vops = &ufs_hba_exynos_ops;
const struct exynos_ufs_drv_data *drv_data =
device_get_match_data(dev);
err = ufshcd_pltfrm_init(pdev, &ufs_hba_exynos_ops);
if (drv_data && drv_data->vops)
vops = drv_data->vops;
err = ufshcd_pltfrm_init(pdev, vops);
if (err)
dev_err(dev, "ufshcd_pltfrm_init() failed %d\n", err);
@@ -1261,8 +1544,35 @@ static struct exynos_ufs_uic_attr exynos7_uic_attr = {
.pa_dbg_option_suite = 0x30103,
};
static struct exynos_ufs_drv_data exynosauto_ufs_drvs = {
.uic_attr = &exynos7_uic_attr,
.quirks = UFSHCD_QUIRK_PRDT_BYTE_GRAN |
UFSHCI_QUIRK_SKIP_RESET_INTR_AGGR |
UFSHCD_QUIRK_BROKEN_OCS_FATAL_ERROR |
UFSHCD_QUIRK_SKIP_DEF_UNIPRO_TIMEOUT_SETTING,
.opts = EXYNOS_UFS_OPT_BROKEN_AUTO_CLK_CTRL |
EXYNOS_UFS_OPT_SKIP_CONFIG_PHY_ATTR |
EXYNOS_UFS_OPT_BROKEN_RX_SEL_IDX,
.drv_init = exynosauto_ufs_drv_init,
.post_hce_enable = exynosauto_ufs_post_hce_enable,
.pre_link = exynosauto_ufs_pre_link,
.pre_pwr_change = exynosauto_ufs_pre_pwr_change,
.post_pwr_change = exynosauto_ufs_post_pwr_change,
};
static struct exynos_ufs_drv_data exynosauto_ufs_vh_drvs = {
.vops = &ufs_hba_exynosauto_vh_ops,
.quirks = UFSHCD_QUIRK_PRDT_BYTE_GRAN |
UFSHCI_QUIRK_SKIP_RESET_INTR_AGGR |
UFSHCD_QUIRK_BROKEN_OCS_FATAL_ERROR |
UFSHCI_QUIRK_BROKEN_HCE |
UFSHCD_QUIRK_BROKEN_UIC_CMD |
UFSHCD_QUIRK_SKIP_PH_CONFIGURATION |
UFSHCD_QUIRK_SKIP_DEF_UNIPRO_TIMEOUT_SETTING,
.opts = EXYNOS_UFS_OPT_BROKEN_RX_SEL_IDX,
};
static struct exynos_ufs_drv_data exynos_ufs_drvs = {
.compatible = "samsung,exynos7-ufs",
.uic_attr = &exynos7_uic_attr,
.quirks = UFSHCD_QUIRK_PRDT_BYTE_GRAN |
UFSHCI_QUIRK_BROKEN_REQ_LIST_CLR |
@@ -1287,6 +1597,10 @@ static struct exynos_ufs_drv_data exynos_ufs_drvs = {
static const struct of_device_id exynos_ufs_of_match[] = {
{ .compatible = "samsung,exynos7-ufs",
.data = &exynos_ufs_drvs },
{ .compatible = "samsung,exynosautov9-ufs",
.data = &exynosauto_ufs_drvs },
{ .compatible = "samsung,exynosautov9-ufs-vh",
.data = &exynosauto_ufs_vh_drvs },
{},
};

View File

@@ -56,6 +56,22 @@
#define TX_GRAN_NVAL_10_08 0x0296
#define TX_GRAN_NVAL_H(v) (((v) >> 8) & 0x3)
#define VND_TX_CLK_PRD 0xAA
#define VND_TX_CLK_PRD_EN 0xA9
#define VND_TX_LINERESET_PVALUE0 0xAD
#define VND_TX_LINERESET_PVALUE1 0xAC
#define VND_TX_LINERESET_PVALUE2 0xAB
#define TX_LINE_RESET_TIME 3200
#define VND_RX_CLK_PRD 0x12
#define VND_RX_CLK_PRD_EN 0x11
#define VND_RX_LINERESET_VALUE0 0x1D
#define VND_RX_LINERESET_VALUE1 0x1C
#define VND_RX_LINERESET_VALUE2 0x1B
#define RX_LINE_RESET_TIME 1000
#define RX_FILLER_ENABLE 0x0316
#define RX_FILLER_EN (1 << 1)
#define RX_LINERESET_VAL 0x0317
@@ -99,7 +115,7 @@ struct exynos_ufs;
#define PA_HIBERN8TIME_VAL 0x20
#define PCLK_AVAIL_MIN 70000000
#define PCLK_AVAIL_MAX 133000000
#define PCLK_AVAIL_MAX 167000000
struct exynos_ufs_uic_attr {
/* TX Attributes */
@@ -142,7 +158,7 @@ struct exynos_ufs_uic_attr {
};
struct exynos_ufs_drv_data {
char *compatible;
const struct ufs_hba_variant_ops *vops;
struct exynos_ufs_uic_attr *uic_attr;
unsigned int quirks;
unsigned int opts;
@@ -154,6 +170,8 @@ struct exynos_ufs_drv_data {
struct ufs_pa_layer_attr *pwr);
int (*post_pwr_change)(struct exynos_ufs *ufs,
struct ufs_pa_layer_attr *pwr);
int (*pre_hce_enable)(struct exynos_ufs *ufs);
int (*post_hce_enable)(struct exynos_ufs *ufs);
};
struct ufs_phy_time_cfg {
@@ -191,7 +209,9 @@ struct exynos_ufs {
struct ufs_pa_layer_attr dev_req_params;
struct ufs_phy_time_cfg t_cfg;
ktime_t entry_hibern8_t;
struct exynos_ufs_drv_data *drv_data;
const struct exynos_ufs_drv_data *drv_data;
struct regmap *sysreg;
u32 shareability_reg_offset;
u32 opts;
#define EXYNOS_UFS_OPT_HAS_APB_CLK_CTRL BIT(0)
@@ -199,6 +219,7 @@ struct exynos_ufs {
#define EXYNOS_UFS_OPT_BROKEN_AUTO_CLK_CTRL BIT(2)
#define EXYNOS_UFS_OPT_BROKEN_RX_SEL_IDX BIT(3)
#define EXYNOS_UFS_OPT_USE_SW_HIBERN8_TIMER BIT(4)
#define EXYNOS_UFS_OPT_SKIP_CONFIG_PHY_ATTR BIT(5)
};
#define for_each_ufs_rx_lane(ufs, i) \

View File

@@ -135,6 +135,14 @@ enum {
UFSHCD_CAN_QUEUE = 32,
};
static const char *const ufshcd_state_name[] = {
[UFSHCD_STATE_RESET] = "reset",
[UFSHCD_STATE_OPERATIONAL] = "operational",
[UFSHCD_STATE_ERROR] = "error",
[UFSHCD_STATE_EH_SCHEDULED_FATAL] = "eh_fatal",
[UFSHCD_STATE_EH_SCHEDULED_NON_FATAL] = "eh_non_fatal",
};
/* UFSHCD error handling flags */
enum {
UFSHCD_EH_IN_PROGRESS = (1 << 0),
@@ -239,7 +247,6 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up);
static irqreturn_t ufshcd_intr(int irq, void *__hba);
static int ufshcd_change_power_mode(struct ufs_hba *hba,
struct ufs_pa_layer_attr *pwr_mode);
static void ufshcd_schedule_eh_work(struct ufs_hba *hba);
static int ufshcd_setup_hba_vreg(struct ufs_hba *hba, bool on);
static int ufshcd_setup_vreg(struct ufs_hba *hba, bool on);
static inline int ufshcd_config_vreg_hpm(struct ufs_hba *hba,
@@ -718,7 +725,7 @@ static inline bool ufshcd_is_device_present(struct ufs_hba *hba)
* This function is used to get the OCS field from UTRD
* Returns the OCS field in the UTRD
*/
static inline int ufshcd_get_tr_ocs(struct ufshcd_lrb *lrbp)
static enum utp_ocs ufshcd_get_tr_ocs(struct ufshcd_lrb *lrbp)
{
return le32_to_cpu(lrbp->utr_descriptor_ptr->header.dword_2) & MASK_OCS;
}
@@ -2331,6 +2338,9 @@ int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd)
int ret;
unsigned long flags;
if (hba->quirks & UFSHCD_QUIRK_BROKEN_UIC_CMD)
return 0;
ufshcd_hold(hba, false);
mutex_lock(&hba->uic_cmd_mutex);
ufshcd_add_delay_before_dme_cmd(hba);
@@ -2375,17 +2385,24 @@ static int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
cpu_to_le16(sg_segments * hba->sg_entry_size);
else
lrbp->utr_descriptor_ptr->prd_table_length =
cpu_to_le16((u16) (sg_segments));
cpu_to_le16(sg_segments);
prd = (struct ufshcd_sg_entry *)lrbp->ucd_prdt_ptr;
scsi_for_each_sg(cmd, sg, sg_segments, i) {
prd->size =
cpu_to_le32(((u32) sg_dma_len(sg))-1);
prd->base_addr =
cpu_to_le32(lower_32_bits(sg->dma_address));
prd->upper_addr =
cpu_to_le32(upper_32_bits(sg->dma_address));
const unsigned int len = sg_dma_len(sg);
/*
* From the UFSHCI spec: "Data Byte Count (DBC): A '0'
* based value that indicates the length, in bytes, of
* the data block. A maximum of length of 256KB may
* exist for any entry. Bits 1:0 of this field shall be
* 11b to indicate Dword granularity. A value of '3'
* indicates 4 bytes, '7' indicates 8 bytes, etc."
*/
WARN_ONCE(len > 256 * 1024, "len = %#x\n", len);
prd->size = cpu_to_le32(len - 1);
prd->addr = cpu_to_le64(sg->dma_address);
prd->reserved = 0;
prd = (void *)prd + hba->sg_entry_size;
}
@@ -5110,7 +5127,7 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
{
int result = 0;
int scsi_status;
int ocs;
enum utp_ocs ocs;
/* overall command status of utrd */
ocs = ufshcd_get_tr_ocs(lrbp);
@@ -5269,11 +5286,9 @@ static irqreturn_t ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status)
* __ufshcd_transfer_req_compl - handle SCSI and query command completion
* @hba: per adapter instance
* @completed_reqs: bitmask that indicates which requests to complete
* @retry_requests: whether to ask the SCSI core to retry completed requests
*/
static void __ufshcd_transfer_req_compl(struct ufs_hba *hba,
unsigned long completed_reqs,
bool retry_requests)
unsigned long completed_reqs)
{
struct ufshcd_lrb *lrbp;
struct scsi_cmnd *cmd;
@@ -5290,8 +5305,7 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba,
if (unlikely(ufshcd_should_inform_monitor(hba, lrbp)))
ufshcd_update_monitor(hba, lrbp);
ufshcd_add_command_trace(hba, index, UFS_CMD_COMP);
result = retry_requests ? DID_BUS_BUSY << 16 :
ufshcd_transfer_rsp_status(hba, lrbp);
result = ufshcd_transfer_rsp_status(hba, lrbp);
scsi_dma_unmap(cmd);
cmd->result = result;
ufshcd_crypto_clear_prdt(hba, lrbp);
@@ -5319,14 +5333,12 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba,
/**
* ufshcd_transfer_req_compl - handle SCSI and query command completion
* @hba: per adapter instance
* @retry_requests: whether or not to ask to retry requests
*
* Returns
* IRQ_HANDLED - If interrupt is valid
* IRQ_NONE - If invalid interrupt
*/
static irqreturn_t ufshcd_transfer_req_compl(struct ufs_hba *hba,
bool retry_requests)
static irqreturn_t ufshcd_transfer_req_compl(struct ufs_hba *hba)
{
unsigned long completed_reqs, flags;
u32 tr_doorbell;
@@ -5355,8 +5367,7 @@ static irqreturn_t ufshcd_transfer_req_compl(struct ufs_hba *hba,
spin_unlock_irqrestore(&hba->outstanding_lock, flags);
if (completed_reqs) {
__ufshcd_transfer_req_compl(hba, completed_reqs,
retry_requests);
__ufshcd_transfer_req_compl(hba, completed_reqs);
return IRQ_HANDLED;
} else {
return IRQ_NONE;
@@ -5856,13 +5867,7 @@ out:
/* Complete requests that have door-bell cleared */
static void ufshcd_complete_requests(struct ufs_hba *hba)
{
ufshcd_transfer_req_compl(hba, /*retry_requests=*/false);
ufshcd_tmc_handler(hba);
}
static void ufshcd_retry_aborted_requests(struct ufs_hba *hba)
{
ufshcd_transfer_req_compl(hba, /*retry_requests=*/true);
ufshcd_transfer_req_compl(hba);
ufshcd_tmc_handler(hba);
}
@@ -5944,9 +5949,10 @@ static inline bool ufshcd_is_saved_err_fatal(struct ufs_hba *hba)
(hba->saved_err & (INT_FATAL_ERRORS | UFSHCD_UIC_HIBERN8_MASK));
}
/* host lock must be held before calling this func */
static inline void ufshcd_schedule_eh_work(struct ufs_hba *hba)
void ufshcd_schedule_eh_work(struct ufs_hba *hba)
{
lockdep_assert_held(hba->host->host_lock);
/* handle fatal errors only when link is not in error state */
if (hba->ufshcd_state != UFSHCD_STATE_ERROR) {
if (hba->force_reset || ufshcd_is_link_broken(hba) ||
@@ -6106,6 +6112,13 @@ static void ufshcd_err_handler(struct work_struct *work)
hba = container_of(work, struct ufs_hba, eh_work);
dev_info(hba->dev,
"%s started; HBA state %s; powered %d; shutting down %d; saved_err = %d; saved_uic_err = %d; force_reset = %d%s\n",
__func__, ufshcd_state_name[hba->ufshcd_state],
hba->is_powered, hba->shutting_down, hba->saved_err,
hba->saved_uic_err, hba->force_reset,
ufshcd_is_link_broken(hba) ? "; link is broken" : "");
down(&hba->host_sem);
spin_lock_irqsave(hba->host->host_lock, flags);
if (ufshcd_err_handling_should_stop(hba)) {
@@ -6200,6 +6213,8 @@ again:
err_xfer = true;
goto lock_skip_pending_xfer_clear;
}
dev_err(hba->dev, "Aborted tag %d / CDB %#02x\n", tag,
hba->lrb[tag].cmd ? hba->lrb[tag].cmd->cmnd[0] : -1);
}
/* Clear pending task management requests */
@@ -6211,7 +6226,8 @@ again:
}
lock_skip_pending_xfer_clear:
ufshcd_retry_aborted_requests(hba);
/* Complete the requests that are cleared by s/w */
ufshcd_complete_requests(hba);
spin_lock_irqsave(hba->host->host_lock, flags);
hba->silence_err_logs = false;
@@ -6279,6 +6295,9 @@ skip_err_handling:
spin_unlock_irqrestore(hba->host->host_lock, flags);
ufshcd_err_handling_unprepare(hba);
up(&hba->host_sem);
dev_info(hba->dev, "%s finished; HBA state %s\n", __func__,
ufshcd_state_name[hba->ufshcd_state]);
}
/**
@@ -6505,7 +6524,7 @@ static irqreturn_t ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
retval |= ufshcd_tmc_handler(hba);
if (intr_status & UTP_TRANSFER_REQ_COMPL)
retval |= ufshcd_transfer_req_compl(hba, /*retry_requests=*/false);
retval |= ufshcd_transfer_req_compl(hba);
return retval;
}
@@ -6577,6 +6596,10 @@ static int ufshcd_clear_tm_cmd(struct ufs_hba *hba, int tag)
err = ufshcd_wait_for_register(hba,
REG_UTP_TASK_REQ_DOOR_BELL,
mask, 0, 1000, 1000);
dev_err(hba->dev, "Clearing task management function with tag %d %s\n",
tag, err ? "succeeded" : "failed");
out:
return err;
}
@@ -6669,7 +6692,8 @@ static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id,
u8 tm_function, u8 *tm_response)
{
struct utp_task_req_desc treq = { { 0 }, };
int ocs_value, err;
enum utp_ocs ocs_value;
int err;
/* Configure task request descriptor */
treq.header.dword_0 = cpu_to_le32(UTP_REQ_DESC_INT_CMD);
@@ -6847,7 +6871,7 @@ int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba,
int err;
enum dev_cmd_type cmd_type = DEV_CMD_TYPE_QUERY;
struct utp_task_req_desc treq = { { 0 }, };
int ocs_value;
enum utp_ocs ocs_value;
u8 tm_f = be32_to_cpu(req_upiu->header.dword_1) >> 16 & MASK_TM_FUNC;
switch (msgcode) {
@@ -6925,7 +6949,7 @@ static int ufshcd_eh_device_reset_handler(struct scsi_cmnd *cmd)
err = ufshcd_clear_cmd(hba, pos);
if (err)
break;
__ufshcd_transfer_req_compl(hba, 1U << pos, false);
__ufshcd_transfer_req_compl(hba, 1U << pos);
}
}
@@ -7087,7 +7111,7 @@ static int ufshcd_abort(struct scsi_cmnd *cmd)
dev_err(hba->dev,
"%s: cmd was completed, but without a notifying intr, tag = %d",
__func__, tag);
__ufshcd_transfer_req_compl(hba, 1UL << tag, /*retry_requests=*/false);
__ufshcd_transfer_req_compl(hba, 1UL << tag);
goto release;
}
@@ -7153,7 +7177,7 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba)
ufshpb_reset_host(hba);
ufshcd_hba_stop(hba);
hba->silence_err_logs = true;
ufshcd_retry_aborted_requests(hba);
ufshcd_complete_requests(hba);
hba->silence_err_logs = false;
/* scale up clocks to max frequency before full reinitialization */
@@ -8034,6 +8058,9 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params)
if (ret)
goto out;
if (hba->quirks & UFSHCD_QUIRK_SKIP_PH_CONFIGURATION)
goto out;
/* Debug counters initialization */
ufshcd_clear_dbg_ufs_stats(hba);
@@ -9805,6 +9832,11 @@ static int __init ufshcd_core_init(void)
{
int ret;
/* Verify that there are no gaps in struct utp_transfer_cmd_desc. */
static_assert(sizeof(struct utp_transfer_cmd_desc) ==
2 * ALIGNED_UPIU_SIZE +
SG_ALL * sizeof(struct ufshcd_sg_entry));
ufs_debugfs_init();
ret = scsi_register_driver(&ufs_dev_wlun_template.gendrv);

View File

@@ -590,6 +590,17 @@ enum ufshcd_quirks {
*/
UFSHCD_QUIRK_ALIGN_SG_WITH_PAGE_SIZE = 1 << 14,
/*
* This quirk needs to be enabled if the host controller does not
* support UIC command
*/
UFSHCD_QUIRK_BROKEN_UIC_CMD = 1 << 15,
/*
* This quirk needs to be enabled if the host controller cannot
* support physical host configuration.
*/
UFSHCD_QUIRK_SKIP_PH_CONFIGURATION = 1 << 16,
/*
* This quirk needs to be enabled if the host controller supports inline
* encryption, but it needs to initialize the crypto capabilities in a
@@ -1048,6 +1059,7 @@ int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask,
void ufshcd_parse_dev_ref_clk_freq(struct ufs_hba *hba, struct clk *refclk);
void ufshcd_update_evt_hist(struct ufs_hba *hba, u32 id, u32 val);
void ufshcd_hba_stop(struct ufs_hba *hba);
void ufshcd_schedule_eh_work(struct ufs_hba *hba);
static inline void check_upiu_size(void)
{

View File

@@ -389,7 +389,7 @@ enum {
};
/* Overall command status values */
enum {
enum utp_ocs {
OCS_SUCCESS = 0x0,
OCS_INVALID_CMD_TABLE_ATTR = 0x1,
OCS_INVALID_PRDT_ATTR = 0x2,
@@ -402,6 +402,9 @@ enum {
OCS_INVALID_CRYPTO_CONFIG = 0x9,
OCS_GENERAL_CRYPTO_ERROR = 0xA,
OCS_INVALID_COMMAND_STATUS = 0x0F,
};
enum {
MASK_OCS = 0x0F,
};
@@ -412,14 +415,12 @@ enum {
/**
* struct ufshcd_sg_entry - UFSHCI PRD Entry
* @base_addr: Lower 32bit physical address DW-0
* @upper_addr: Upper 32bit physical address DW-1
* @addr: Physical address; DW-0 and DW-1.
* @reserved: Reserved for future use DW-2
* @size: size of physical segment DW-3
*/
struct ufshcd_sg_entry {
__le32 base_addr;
__le32 upper_addr;
__le64 addr;
__le32 reserved;
__le32 size;
/*
@@ -429,7 +430,7 @@ struct ufshcd_sg_entry {
};
/**
* struct utp_transfer_cmd_desc - UFS Command Descriptor structure
* struct utp_transfer_cmd_desc - UTP Command Descriptor (UCD)
* @command_upiu: Command UPIU Frame address
* @response_upiu: Response UPIU Frame address
* @prd_table: Physical Region Descriptor: an array of SG_ALL struct
@@ -459,7 +460,7 @@ struct request_desc_header {
};
/**
* struct utp_transfer_req_desc - UTRD structure
* struct utp_transfer_req_desc - UTP Transfer Request Descriptor (UTRD)
* @header: UTRD header DW-0 to DW-3
* @command_desc_base_addr_lo: UCD base address low DW-4
* @command_desc_base_addr_hi: UCD base address high DW-5

View File

@@ -394,8 +394,6 @@ int ufshpb_prep(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
if (!ufshpb_is_supported_chunk(hpb, transfer_len))
return 0;
WARN_ON_ONCE(transfer_len > HPB_MULTI_CHUNK_HIGH);
if (hpb->is_hcm) {
/*
* in host control mode, reads are the main source for
@@ -1572,7 +1570,7 @@ static void ufshpb_lu_parameter_init(struct ufs_hba *hba,
if (ufshpb_is_legacy(hba))
hpb->pre_req_max_tr_len = HPB_LEGACY_CHUNK_HIGH;
else
hpb->pre_req_max_tr_len = HPB_MULTI_CHUNK_HIGH;
hpb->pre_req_max_tr_len = hpb_dev_info->max_hpb_single_cmd;
hpb->lu_pinned_start = hpb_lu_info->pinned_start;
hpb->lu_pinned_end = hpb_lu_info->num_pinned ?
@@ -2582,7 +2580,7 @@ void ufshpb_get_dev_info(struct ufs_hba *hba, u8 *desc_buf)
{
struct ufshpb_dev_info *hpb_dev_info = &hba->ufshpb_dev;
int version, ret;
u32 max_hpb_single_cmd = HPB_MULTI_CHUNK_LOW;
int max_single_cmd;
hpb_dev_info->control_mode = desc_buf[DEVICE_DESC_PARAM_HPB_CONTROL];
@@ -2598,18 +2596,22 @@ void ufshpb_get_dev_info(struct ufs_hba *hba, u8 *desc_buf)
if (version == HPB_SUPPORT_LEGACY_VERSION)
hpb_dev_info->is_legacy = true;
ret = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR,
QUERY_ATTR_IDN_MAX_HPB_SINGLE_CMD, 0, 0, &max_hpb_single_cmd);
if (ret)
dev_err(hba->dev, "%s: idn: read max size of single hpb cmd query request failed",
__func__);
hpb_dev_info->max_hpb_single_cmd = max_hpb_single_cmd;
/*
* Get the number of user logical unit to check whether all
* scsi_device finish initialization
*/
hpb_dev_info->num_lu = desc_buf[DEVICE_DESC_PARAM_NUM_LU];
if (hpb_dev_info->is_legacy)
return;
ret = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR,
QUERY_ATTR_IDN_MAX_HPB_SINGLE_CMD, 0, 0, &max_single_cmd);
if (ret)
hpb_dev_info->max_hpb_single_cmd = HPB_LEGACY_CHUNK_HIGH;
else
hpb_dev_info->max_hpb_single_cmd = min(max_single_cmd + 1, HPB_MULTI_CHUNK_HIGH);
}
void ufshpb_init(struct ufs_hba *hba)

View File

@@ -31,7 +31,6 @@
/* hpb support chunk size */
#define HPB_LEGACY_CHUNK_HIGH 1
#define HPB_MULTI_CHUNK_LOW 7
#define HPB_MULTI_CHUNK_HIGH 255
/* hpb vender defined opcode */

View File

@@ -50,15 +50,6 @@ EXPORT_SYMBOL(core_tmr_alloc_req);
void core_tmr_release_req(struct se_tmr_req *tmr)
{
struct se_device *dev = tmr->tmr_dev;
unsigned long flags;
if (dev) {
spin_lock_irqsave(&dev->se_tmr_lock, flags);
list_del_init(&tmr->tmr_list);
spin_unlock_irqrestore(&dev->se_tmr_lock, flags);
}
kfree(tmr);
}
@@ -156,13 +147,6 @@ void core_tmr_abort_task(
se_cmd->state_active = false;
spin_unlock_irqrestore(&dev->queues[i].lock, flags);
/*
* Ensure that this ABORT request is visible to the LU
* RESET code.
*/
if (!tmr->tmr_dev)
WARN_ON_ONCE(transport_lookup_tmr_lun(tmr->task_cmd) < 0);
if (dev->transport->tmr_notify)
dev->transport->tmr_notify(dev, TMR_ABORT_TASK,
&aborted_list);
@@ -234,6 +218,7 @@ static void core_tmr_drain_tmr_list(
}
list_move_tail(&tmr_p->tmr_list, &drain_tmr_list);
tmr_p->tmr_dev = NULL;
}
spin_unlock_irqrestore(&dev->se_tmr_lock, flags);

View File

@@ -676,6 +676,21 @@ static void target_remove_from_state_list(struct se_cmd *cmd)
spin_unlock_irqrestore(&dev->queues[cmd->cpuid].lock, flags);
}
static void target_remove_from_tmr_list(struct se_cmd *cmd)
{
struct se_device *dev = NULL;
unsigned long flags;
if (cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)
dev = cmd->se_tmr_req->tmr_dev;
if (dev) {
spin_lock_irqsave(&dev->se_tmr_lock, flags);
if (cmd->se_tmr_req->tmr_dev)
list_del_init(&cmd->se_tmr_req->tmr_list);
spin_unlock_irqrestore(&dev->se_tmr_lock, flags);
}
}
/*
* This function is called by the target core after the target core has
* finished processing a SCSI command or SCSI TMF. Both the regular command
@@ -687,13 +702,6 @@ static int transport_cmd_check_stop_to_fabric(struct se_cmd *cmd)
{
unsigned long flags;
target_remove_from_state_list(cmd);
/*
* Clear struct se_cmd->se_lun before the handoff to FE.
*/
cmd->se_lun = NULL;
spin_lock_irqsave(&cmd->t_state_lock, flags);
/*
* Determine if frontend context caller is requesting the stopping of
@@ -728,8 +736,16 @@ static void transport_lun_remove_cmd(struct se_cmd *cmd)
if (!lun)
return;
target_remove_from_state_list(cmd);
target_remove_from_tmr_list(cmd);
if (cmpxchg(&cmd->lun_ref_active, true, false))
percpu_ref_put(&lun->lun_ref);
/*
* Clear struct se_cmd->se_lun before the handoff to FE.
*/
cmd->se_lun = NULL;
}
static void target_complete_failure_work(struct work_struct *work)

View File

@@ -73,7 +73,7 @@ enum scsi_cmnd_submitter {
struct scsi_cmnd {
struct scsi_request req;
struct scsi_device *device;
struct list_head eh_entry; /* entry for the host eh_cmd_q */
struct list_head eh_entry; /* entry for the host eh_abort_list/eh_cmd_q */
struct delayed_work abort_work;
struct rcu_head rcu;

View File

@@ -226,12 +226,6 @@ struct scsi_device {
struct device sdev_gendev,
sdev_dev;
/*
* The array size 6 provides space for one attribute group for the
* SCSI core, four attribute groups defined by SCSI LLDs and one
* terminating NULL pointer.
*/
const struct attribute_group *gendev_attr_groups[6];
struct execute_work ew; /* used to get process context on put */
struct work_struct requeue_work;

View File

@@ -551,6 +551,7 @@ struct Scsi_Host {
struct mutex scan_mutex;/* serialize scanning activity */
struct list_head eh_abort_list;
struct list_head eh_cmd_q;
struct task_struct * ehandler; /* Error recovery thread. */
struct completion * eh_action; /* Wait for specific actions on the