diff --git a/qla2x00t/qla2x00-target/qla2x00t.c b/qla2x00t/qla2x00-target/qla2x00t.c index 13a3afff3..cc2d65502 100644 --- a/qla2x00t/qla2x00-target/qla2x00t.c +++ b/qla2x00t/qla2x00-target/qla2x00t.c @@ -1547,6 +1547,8 @@ static int q2t_target_release(struct scst_tgt *scst_tgt) q2t_target_stop(scst_tgt); + cancel_work_sync(&tgt->rscn_reg_work); + ha->q2t_tgt = NULL; scst_tgt_set_tgt_priv(scst_tgt, NULL); @@ -4173,11 +4175,39 @@ out: return res; } +static void q2t_rscn_reg_work(struct work_struct *work) +{ + struct q2t_tgt *tgt = container_of(work, struct q2t_tgt, rscn_reg_work); + scsi_qla_host_t *ha = tgt->ha; + int ret; + + TRACE_ENTRY(); + + if ((ha->host->active_mode & MODE_INITIATOR) == 0) { + /* + * The QLogic firmware and qla2xxx do not register for RSCNs in + * target-only mode, so do that explicitly. + */ + ret = qla2x00_send_change_request(ha, 0x3, ha->vp_idx); + if (ret != QLA_SUCCESS) + PRINT_INFO("qla2x00t(%ld): RSCN registration failed: " + "%#x (OK for non-fabric setups)", + ha->host_no, ret); + else + TRACE_MGMT_DBG("qla2x00t(%ld): RSCN registration succeeded", + ha->host_no); + } + + TRACE_EXIT(); + return; +} + /* * pha->hardware_lock supposed to be held on entry. Might drop it, then reacquire */ static int q24_handle_els(scsi_qla_host_t *ha, notify24xx_entry_t *iocb) { + struct q2t_tgt *tgt = ha->tgt; int res = 1; /* send notify ack */ struct q2t_sess *sess; int loop_id; @@ -4189,6 +4219,13 @@ static int q24_handle_els(scsi_qla_host_t *ha, notify24xx_entry_t *iocb) switch (iocb->status_subcode) { case ELS_PLOGI: + /* + * HACK. Let's do it on PLOGI, because seems there is no other + * simple place, from where it can be called. In the worst + * case, we will just reinstall RSCNs once again, it's harmless. + */ + schedule_work(&tgt->rscn_reg_work); + break; case ELS_FLOGI: case ELS_PRLI: break; @@ -5886,6 +5923,7 @@ static int q2t_add_target(scsi_qla_host_t *ha) tgt->ha = ha; init_waitqueue_head(&tgt->waitQ); + INIT_WORK(&tgt->rscn_reg_work, q2t_rscn_reg_work); INIT_LIST_HEAD(&tgt->sess_list); INIT_LIST_HEAD(&tgt->del_sess_list); INIT_DELAYED_WORK(&tgt->sess_del_work, q2t_del_sess_work_fn); diff --git a/qla2x00t/qla2x00-target/qla2x00t.h b/qla2x00t/qla2x00-target/qla2x00t.h index 7c98dc7f8..b83ab0468 100644 --- a/qla2x00t/qla2x00-target/qla2x00t.h +++ b/qla2x00t/qla2x00-target/qla2x00t.h @@ -137,7 +137,9 @@ struct q2t_tgt { */ unsigned long tgt_stop; /* the driver is being stopped */ - /* Count of sessions refering q2t_tgt. Protected by hardware_lock. */ + struct work_struct rscn_reg_work; + + /* Count of sessions referring q2t_tgt. Protected by hardware_lock. */ int sess_count; /* diff --git a/qla2x00t/qla_mbx.c b/qla2x00t/qla_mbx.c index f87985433..32d133d78 100644 --- a/qla2x00t/qla_mbx.c +++ b/qla2x00t/qla_mbx.c @@ -3035,9 +3035,9 @@ qla2x00_send_change_request(scsi_qla_host_t *ha, uint16_t format, /* * This command is implicitly executed by firmware during login for the - * physical hosts + * physical hosts if initiator mode is enabled. */ - if (vp_idx == 0) + if (vp_idx == 0 && (ha->host->active_mode & MODE_INITIATOR)) return QLA_FUNCTION_FAILED; mcp->mb[0] = MBC_SEND_CHANGE_REQUEST; @@ -3058,6 +3058,7 @@ qla2x00_send_change_request(scsi_qla_host_t *ha, uint16_t format, return rval; } +EXPORT_SYMBOL(qla2x00_send_change_request); int qla2x00_dump_ram(scsi_qla_host_t *ha, dma_addr_t req_dma, uint32_t addr, diff --git a/scst/src/dev_handlers/scst_user.c b/scst/src/dev_handlers/scst_user.c index 3b0ebc8bd..5973f631d 100644 --- a/scst/src/dev_handlers/scst_user.c +++ b/scst/src/dev_handlers/scst_user.c @@ -2261,7 +2261,7 @@ static void dev_user_unjam_cmd(struct scst_user_cmd *ucmd, int busy, scst_set_busy(ucmd->cmd); else scst_set_cmd_error(ucmd->cmd, - SCST_LOAD_SENSE(scst_sense_internal_failure)); + SCST_LOAD_SENSE(scst_sense_lun_not_supported)); } scst_set_cmd_abnormal_done_state(ucmd->cmd); @@ -2292,7 +2292,7 @@ static void dev_user_unjam_cmd(struct scst_user_cmd *ucmd, int busy, scst_set_busy(ucmd->cmd); else scst_set_cmd_error(ucmd->cmd, - SCST_LOAD_SENSE(scst_sense_internal_failure)); + SCST_LOAD_SENSE(scst_sense_lun_not_supported)); } ucmd->cmd->scst_cmd_done(ucmd->cmd, SCST_CMD_STATE_DEFAULT, diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index 57ee0572e..32dfc8665 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -3737,9 +3737,10 @@ static int vdisk_caching_pg(unsigned char *p, int pcontrol, if (!virt_dev->nv_cache && vdev_saved_mode_pages_enabled) caching_pg[0] |= 0x80; + memcpy(p, caching_pg, sizeof(caching_pg)); + switch (pcontrol) { case 0: /* current */ - memcpy(p, caching_pg, sizeof(caching_pg)); p[2] |= (virt_dev->wt_flag || virt_dev->nv_cache) ? 0 : WCE; break; case 1: /* changeable */ @@ -3748,11 +3749,9 @@ static int vdisk_caching_pg(unsigned char *p, int pcontrol, p[2] |= WCE; break; case 2: /* default */ - memcpy(p, caching_pg, sizeof(caching_pg)); p[2] |= (DEF_WRITE_THROUGH || virt_dev->nv_cache) ? 0 : WCE; break; case 3: /* saved */ - memcpy(p, caching_pg, sizeof(caching_pg)); p[2] |= (virt_dev->wt_flag_saved || virt_dev->nv_cache) ? 0 : WCE; break; default: diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index e63347bdc..122352ca8 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -930,15 +930,15 @@ static const struct scst_sdbops scst_scsi_op_table[] = { .info_op_name = "WRITE BUFFER", .info_data_direction = SCST_DATA_WRITE, .info_op_flags = SCST_SMALL_TIMEOUT, - .info_len_off = 5, .info_len_len = 2, - .get_cdb_info = get_cdb_info_len_2}, + .info_len_off = 6, .info_len_len = 3, + .get_cdb_info = get_cdb_info_len_3}, {.ops = 0x3C, .devkey = "OOOOOOOOOOOOOOOO", .info_op_name = "READ BUFFER", .info_data_direction = SCST_DATA_READ, .info_op_flags = SCST_SMALL_TIMEOUT | SCST_WRITE_EXCL_ALLOWED, - .info_len_off = 5, .info_len_len = 2, - .get_cdb_info = get_cdb_info_len_2}, + .info_len_off = 6, .info_len_len = 3, + .get_cdb_info = get_cdb_info_len_3}, {.ops = 0x3D, .devkey = " O O ", .info_op_name = "UPDATE BLOCK", .info_data_direction = SCST_DATA_WRITE, diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index 7e43b6747..dcdc94e8b 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -655,6 +655,9 @@ static int scst_parse_cmd(struct scst_cmd *cmd) goto out; case SCST_CMD_STATE_STOP: + /* + * !! cmd can be dead now! + */ TRACE_DBG("Dev handler %s parse() requested stop " "processing", devt->name); res = SCST_CMD_STATE_RES_CONT_NEXT; @@ -939,11 +942,11 @@ set_res: TRACE_DBG_FLAG(TRACE_DEBUG|TRACE_MINOR, "Atomic context and " "non-WRITE data direction, rescheduling (cmd %p)", cmd); res = SCST_CMD_STATE_RES_NEED_THREAD; - goto out; + /* go through */ } #endif -out: +out_check_compl: #ifdef CONFIG_SCST_EXTRACHECKS if (unlikely(cmd->completed)) { /* Command completed with error */ @@ -1000,6 +1003,7 @@ out: } } +out: TRACE_EXIT_HRES(res); return res; @@ -1010,7 +1014,7 @@ out_hw_error: out_done: scst_set_cmd_abnormal_done_state(cmd); res = SCST_CMD_STATE_RES_CONT_SAME; - goto out; + goto out_check_compl; } static void scst_set_write_len(struct scst_cmd *cmd)