Index: sys/dev/ocs_fc/ocs.h =================================================================== --- sys/dev/ocs_fc/ocs.h +++ sys/dev/ocs_fc/ocs.h @@ -62,13 +62,36 @@ char name[64]; /** label for this context */ } ocs_intr_ctx_t; +typedef struct ocs_fc_rport_db_s { + uint32_t node_id; + uint32_t state; + uint8_t is_target; + uint8_t is_initiator; + + uint32_t port_id; + uint64_t wwnn; + uint64_t wwpn; + uint32_t gone_timer; + +} ocs_fc_target_t; + +#define OCS_TGT_STATE_NONE 0 /* Empty DB slot */ +#define OCS_TGT_STATE_VALID 1 /* Valid*/ +#define OCS_TGT_STATE_LOST 2 /* LOST*/ + typedef struct ocs_fcport_s { - struct cam_sim *sim; - struct cam_path *path; - uint32_t role; + ocs_t *ocs; + struct cam_sim *sim; + struct cam_path *path; + uint32_t role; - ocs_tgt_resource_t targ_rsrc_wildcard; - ocs_tgt_resource_t targ_rsrc[OCS_MAX_LUN]; + ocs_fc_target_t tgt[OCS_MAX_TARGETS]; + int lost_device_time; + struct callout ldt; /* device lost timer */ + struct task ltask; + + ocs_tgt_resource_t targ_rsrc_wildcard; + ocs_tgt_resource_t targ_rsrc[OCS_MAX_LUN]; ocs_vport_spec_t *vport; } ocs_fcport; @@ -169,7 +192,7 @@ uint32_t enable_task_set_full; uint32_t io_in_use; uint32_t io_high_watermark; /**< used to send task set full */ - struct mtx sim_lock; + struct mtx sim_lock; uint32_t config_tgt:1, /**< Configured to support target mode */ config_ini:1; /**< Configured to support initiator mode */ Index: sys/dev/ocs_fc/ocs_cam.c =================================================================== --- sys/dev/ocs_fc/ocs_cam.c +++ sys/dev/ocs_fc/ocs_cam.c @@ -74,6 +74,14 @@ static uint32_t ocs_fcp_change_role(struct ocs_softc *ocs, ocs_fcport *fcp, uint32_t new_role); +static void ocs_ldt(void *arg); +static void ocs_ldt_task(void *arg, int pending); +static void ocs_delete_target(ocs_t *ocs, ocs_fcport *fcp, int tgt); +uint32_t ocs_add_new_tgt(ocs_node_t *node, ocs_fcport *fcp); +uint32_t ocs_update_tgt(ocs_node_t *node, ocs_fcport *fcp, uint32_t tgt_id); + +int32_t ocs_tgt_find(ocs_fcport *fcp, ocs_node_t *node); + static inline ocs_io_t *ocs_scsi_find_io(struct ocs_softc *ocs, uint32_t tag) { @@ -124,12 +132,15 @@ cam_sim_free(sim, FALSE); return 1; } - + + fcp->ocs = ocs; fcp->sim = sim; fcp->path = path; - return 0; + callout_init_mtx(&fcp->ldt, &ocs->sim_lock, 0); + TASK_INIT(&fcp->ltask, 1, ocs_ldt_task, fcp); + return 0; } static int32_t @@ -143,6 +154,9 @@ sim = fcp->sim; path = fcp->path; + callout_drain(&fcp->ldt); + ocs_ldt_task(fcp, 0); + if (fcp->sim) { mtx_lock(&ocs->sim_lock); ocs_tgt_resource_abort(ocs, &fcp->targ_rsrc_wildcard); @@ -672,7 +686,7 @@ inot = (struct ccb_immediate_notify *)STAILQ_FIRST(&trsrc->inot); } - if (!inot) { + if (!inot) { device_printf( ocs->dev, "%s: no INOT for LUN %llx (en=%s) OX_ID %#x\n", __func__, (unsigned long long)lun, trsrc ? (trsrc->enabled ? "T" : "F") : "X", @@ -932,6 +946,26 @@ } +int32_t +ocs_tgt_find(ocs_fcport *fcp, ocs_node_t *node) +{ + ocs_fc_target_t *tgt = NULL; + uint32_t i; + + for (i = 0; i < OCS_MAX_TARGETS; i++) { + tgt = &fcp->tgt[i]; + + if (tgt->state == OCS_TGT_STATE_NONE) + continue; + + if (ocs_node_get_wwpn(node) == tgt->wwpn) { + return i; + } + } + + return -1; +} + /** * @ingroup scsi_api_initiator * @brief receive notification of a new SCSI target node @@ -949,38 +983,150 @@ * * @note */ -int32_t -ocs_scsi_new_target(ocs_node_t *node) + +uint32_t +ocs_update_tgt(ocs_node_t *node, ocs_fcport *fcp, uint32_t tgt_id) { + ocs_fc_target_t *tgt = NULL; + + tgt = &fcp->tgt[tgt_id]; + + tgt->node_id = node->instance_index; + tgt->state = OCS_TGT_STATE_VALID; + + tgt->port_id = node->rnode.fc_id; + tgt->wwpn = ocs_node_get_wwpn(node); + tgt->wwnn = ocs_node_get_wwnn(node); + return 0; +} + +uint32_t +ocs_add_new_tgt(ocs_node_t *node, ocs_fcport *fcp) +{ + uint32_t i; + struct ocs_softc *ocs = node->ocs; union ccb *ccb = NULL; - ocs_fcport *fcp = NULL; - - fcp = node->sport->tgt_data; - if (fcp == NULL) { - printf("%s:FCP is NULL \n", __func__); - return 0; + for (i = 0; i < OCS_MAX_TARGETS; i++) { + if (fcp->tgt[i].state == OCS_TGT_STATE_NONE) + break; } if (NULL == (ccb = xpt_alloc_ccb_nowait())) { device_printf(ocs->dev, "%s: ccb allocation failed\n", __func__); return -1; } - + if (CAM_REQ_CMP != xpt_create_path(&ccb->ccb_h.path, xpt_periph, cam_sim_path(fcp->sim), - node->instance_index, CAM_LUN_WILDCARD)) { + i, CAM_LUN_WILDCARD)) { device_printf( ocs->dev, "%s: target path creation failed\n", __func__); xpt_free_ccb(ccb); return -1; } + ocs_update_tgt(node, fcp, i); xpt_rescan(ccb); + return 0; +} +int32_t +ocs_scsi_new_target(ocs_node_t *node) +{ + ocs_fcport *fcp = NULL; + int32_t i; + + fcp = node->sport->tgt_data; + if (fcp == NULL) { + printf("%s:FCP is NULL \n", __func__); + return 0; + } + + i = ocs_tgt_find(fcp, node); + + if (i < 0) { + ocs_add_new_tgt(node, fcp); + return 0; + } + + ocs_update_tgt(node, fcp, i); return 0; } +static void +ocs_delete_target(ocs_t *ocs, ocs_fcport *fcp, int tgt) +{ + struct cam_path *cpath = NULL; + + if (!fcp->sim) { + device_printf(ocs->dev, "%s: calling with NULL sim\n", __func__); + return; + } + + if (CAM_REQ_CMP == xpt_create_path(&cpath, NULL, cam_sim_path(fcp->sim), + tgt, CAM_LUN_WILDCARD)) { + xpt_async(AC_LOST_DEVICE, cpath, NULL); + + xpt_free_path(cpath); + } +} + +/* + * Device Lost Timer Function- when we have decided that a device was lost, + * we wait a specific period of time prior to telling the OS about lost device. + * + * This timer function gets activated when the device was lost. + * This function fires once a second and then scans the port database + * for devices that are marked dead but still have a virtual target assigned. + * We decrement a counter for that port database entry, and when it hits zero, + * we tell the OS the device was lost. Timer will be stopped when the device + * comes back active or removed from the OS. + */ +static void +ocs_ldt(void *arg) +{ + ocs_fcport *fcp = arg; + taskqueue_enqueue(taskqueue_thread, &fcp->ltask); +} + +static void +ocs_ldt_task(void *arg, int pending) +{ + ocs_fcport *fcp = arg; + ocs_t *ocs = fcp->ocs; + int i, more_to_do = 0; + ocs_fc_target_t *tgt = NULL; + + for (i = 0; i < OCS_MAX_TARGETS; i++) { + tgt = &fcp->tgt[i]; + + if (tgt->state != OCS_TGT_STATE_LOST) { + continue; + } + + if ((tgt->gone_timer != 0) && (ocs->attached)){ + tgt->gone_timer -= 1; + more_to_do++; + continue; + } + + if (tgt->is_target) { + tgt->is_target = 0; + ocs_delete_target(ocs, fcp, i); + } + + tgt->state = OCS_TGT_STATE_NONE; + } + + if (more_to_do) { + callout_reset(&fcp->ldt, hz, ocs_ldt, fcp); + } else { + callout_deactivate(&fcp->ldt); + } + +} + /** * @ingroup scsi_api_initiator * @brief Delete a SCSI target node @@ -1008,8 +1154,9 @@ ocs_scsi_del_target(ocs_node_t *node, ocs_scsi_del_target_reason_e reason) { struct ocs_softc *ocs = node->ocs; - struct cam_path *cpath = NULL; ocs_fcport *fcp = NULL; + ocs_fc_target_t *tgt = NULL; + uint32_t tgt_id; fcp = node->sport->tgt_data; if (fcp == NULL) { @@ -1017,18 +1164,23 @@ return 0; } - if (!fcp->sim) { - device_printf(ocs->dev, "%s: calling with NULL sim\n", __func__); - return OCS_SCSI_CALL_COMPLETE; - } + tgt_id = ocs_tgt_find(fcp, node); + + tgt = &fcp->tgt[tgt_id]; + + // IF in shutdown delete target. + if(!ocs->attached) { + ocs_delete_target(ocs, fcp, tgt_id); + } else { - if (CAM_REQ_CMP == xpt_create_path(&cpath, NULL, cam_sim_path(fcp->sim), - node->instance_index, CAM_LUN_WILDCARD)) { - xpt_async(AC_LOST_DEVICE, cpath, NULL); - - xpt_free_path(cpath); + tgt->state = OCS_TGT_STATE_LOST; + tgt->gone_timer = 30; + if (!callout_active(&fcp->ldt)) { + callout_reset(&fcp->ldt, hz, ocs_ldt, fcp); + } } - return OCS_SCSI_CALL_COMPLETE; + + return 0; } /** @@ -1356,6 +1508,10 @@ } } else if (scsi_status != OCS_SCSI_STATUS_GOOD) { ccb_status = CAM_REQ_CMP_ERR; + ocs_set_ccb_status(ccb, ccb_status); + csio->ccb_h.status |= CAM_DEV_QFRZN; + xpt_freeze_devq(csio->ccb_h.path, 1); + } else { ccb_status = CAM_REQ_CMP; } @@ -1618,7 +1774,26 @@ ocs_scsi_sgl_t sgl[OCS_FC_MAX_SGL]; int32_t sgl_count; - node = ocs_node_get_instance(ocs, ccb_h->target_id); + ocs_fcport *fcp = NULL; + fcp = FCPORT(ocs, cam_sim_bus(xpt_path_sim((ccb)->ccb_h.path))); + if (fcp == NULL) { + device_printf(ocs->dev, "%s: fcp is NULL\n", __func__); + return -1; + } + + if (fcp->tgt[ccb_h->target_id].state == OCS_TGT_STATE_LOST) { + device_printf(ocs->dev, "%s: device LOST %d\n", __func__, + ccb_h->target_id); + return CAM_REQUEUE_REQ; + } + + if (fcp->tgt[ccb_h->target_id].state == OCS_TGT_STATE_NONE) { + device_printf(ocs->dev, "%s: device not ready %d\n", __func__, + ccb_h->target_id); + return CAM_DEV_NOT_THERE; + } + + node = ocs_node_get_instance(ocs, fcp->tgt[ccb_h->target_id].node_id); if (node == NULL) { device_printf(ocs->dev, "%s: no device %d\n", __func__, ccb_h->target_id); @@ -1626,10 +1801,10 @@ } if (!node->targ) { - device_printf(ocs->dev, "%s: not target device %d\n", __func__, + device_printf(ocs->dev, "%s: not target device %d\n", __func__, ccb_h->target_id); - return CAM_DEV_NOT_THERE; - } + return CAM_DEV_NOT_THERE; + } io = ocs_scsi_io_alloc(node, OCS_SCSI_IO_ROLE_ORIGINATOR); if (io == NULL) { @@ -1666,7 +1841,7 @@ csio->cdb_io.cdb_ptr: csio->cdb_io.cdb_bytes, csio->cdb_len, ocs_scsi_initiator_io_cb, ccb); - break; + break; case CAM_DIR_IN: rc = ocs_scsi_send_rd_io(node, io, ccb_h->target_lun, ccb->ccb_h.flags & CAM_CDB_POINTER ? @@ -1702,9 +1877,9 @@ ocs_vport_spec_t *vport = fcp->vport; for (was = 0, i = 0; i < (ocs->num_vports + 1); i++) { - if (FCPORT(ocs, i)->role != KNOB_ROLE_NONE) - was++; - } + if (FCPORT(ocs, i)->role != KNOB_ROLE_NONE) + was++; + } // Physical port if ((was == 0) || (vport == NULL)) { @@ -1743,7 +1918,7 @@ vport->enable_ini = (new_role & KNOB_ROLE_INITIATOR)? 1:0; vport->enable_tgt = (new_role & KNOB_ROLE_TARGET)? 1:0; - if (fcp->role != KNOB_ROLE_NONE) { + if (fcp->role != KNOB_ROLE_NONE) { return ocs_sport_vport_alloc(ocs->domain, vport); } @@ -1774,20 +1949,28 @@ switch (ccb_h->func_code) { case XPT_SCSI_IO: - + if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) { - if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) { - ccb->ccb_h.status = CAM_REQ_INVALID; + if ((ccb->ccb_h.flags & CAM_CDB_PHYS) != 0) { + ccb->ccb_h.status = CAM_REQ_INVALID; xpt_done(ccb); - break; - } - } + break; + } + } rc = ocs_initiator_io(ocs, ccb); if (0 == rc) { ocs_set_ccb_status(ccb, CAM_REQ_INPROG | CAM_SIM_QUEUED); break; } else { + if (rc == CAM_REQUEUE_REQ) { + cam_freeze_devq(ccb->ccb_h.path); + cam_release_devq(ccb->ccb_h.path, RELSIM_RELEASE_AFTER_TIMEOUT, 0, 100, 0); + ccb->ccb_h.status = CAM_REQUEUE_REQ; + xpt_done(ccb); + break; + } + ccb->ccb_h.status &= ~CAM_SIM_QUEUED; if (rc > 0) { ocs_set_ccb_status(ccb, rc); @@ -1838,7 +2021,7 @@ } cpi->hba_misc = PIM_NOBUSRESET | PIM_UNMAPPED; - cpi->hba_misc |= PIM_EXTLUNS | PIM_NOSCAN; + cpi->hba_misc |= PIM_EXTLUNS | PIM_NOSCAN; cpi->hba_inquiry = PI_TAG_ABLE; cpi->max_target = OCS_MAX_TARGETS; @@ -1875,6 +2058,7 @@ struct ccb_trans_settings_scsi *scsi = &cts->proto_specific.scsi; struct ccb_trans_settings_fc *fc = &cts->xport_specific.fc; ocs_xport_stats_t value; + ocs_fcport *fcp = FCPORT(ocs, bus); ocs_node_t *fnode = NULL; if (ocs->ocs_xport != OCS_XPORT_FC) { @@ -1883,7 +2067,7 @@ break; } - fnode = ocs_node_get_instance(ocs, cts->ccb_h.target_id); + fnode = ocs_node_get_instance(ocs, fcp->tgt[cts->ccb_h.target_id].node_id); if (fnode == NULL) { ocs_set_ccb_status(ccb, CAM_DEV_NOT_THERE); xpt_done(ccb); @@ -2066,8 +2250,9 @@ ocs_node_t *node = NULL; ocs_io_t *io = NULL; int32_t rc = 0; + ocs_fcport *fcp = FCPORT(ocs, bus); - node = ocs_node_get_instance(ocs, ccb_h->target_id); + node = ocs_node_get_instance(ocs, fcp->tgt[ccb_h->target_id].node_id); if (node == NULL) { device_printf(ocs->dev, "%s: no device %d\n", __func__, ccb_h->target_id); @@ -2096,7 +2281,7 @@ ocs_set_ccb_status(ccb, CAM_REQ_CMP); } - if (node->fcp2device) { + if (node->fcp2device) { ocs_reset_crn(node, ccb_h->target_lun); } @@ -2358,7 +2543,7 @@ ocs_abort_atio(struct ocs_softc *ocs, union ccb *ccb) { - ocs_io_t *aio = NULL; + ocs_io_t *aio = NULL; ocs_tgt_resource_t *trsrc = NULL; uint32_t status = CAM_REQ_INVALID; struct ccb_hdr *cur = NULL; @@ -2449,12 +2634,13 @@ ocs_abort_initiator_io(struct ocs_softc *ocs, union ccb *accb) { - ocs_node_t *node = NULL; - ocs_io_t *io = NULL; + ocs_node_t *node = NULL; + ocs_io_t *io = NULL; int32_t rc = 0; struct ccb_scsiio *csio = &accb->csio; - node = ocs_node_get_instance(ocs, accb->ccb_h.target_id); + ocs_fcport *fcp = FCPORT(ocs, cam_sim_bus(xpt_path_sim((accb)->ccb_h.path))); + node = ocs_node_get_instance(ocs, fcp->tgt[accb->ccb_h.target_id].node_id); if (node == NULL) { device_printf(ocs->dev, "%s: no device %d\n", __func__, accb->ccb_h.target_id); Index: sys/dev/ocs_fc/ocs_pci.c =================================================================== --- sys/dev/ocs_fc/ocs_pci.c +++ sys/dev/ocs_fc/ocs_pci.c @@ -577,6 +577,8 @@ return -1; } + ocs->attached = FALSE; + rc = ocs_xport_control(ocs->xport, OCS_XPORT_SHUTDOWN); if (rc) { ocs_log_err(ocs, "%s: Transport Shutdown timed out\n", __func__); @@ -599,8 +601,6 @@ bus_dma_tag_destroy(ocs->dmat); ocs_xport_free(ocs->xport); ocs->xport = NULL; - - ocs->attached = FALSE; } Index: sys/dev/ocs_fc/ocs_xport.c =================================================================== --- sys/dev/ocs_fc/ocs_xport.c +++ sys/dev/ocs_fc/ocs_xport.c @@ -251,8 +251,10 @@ ocs_hw_get(&ocs->hw, OCS_HW_MAX_NODES, &max_remote_nodes); - rc = ocs_node_create_pool(ocs, (ocs->max_remote_nodes) ? - ocs->max_remote_nodes : max_remote_nodes); + if (!ocs->max_remote_nodes) + ocs->max_remote_nodes = max_remote_nodes; + + rc = ocs_node_create_pool(ocs, ocs->max_remote_nodes); if (rc) { ocs_log_err(ocs, "Can't allocate node pool\n"); goto ocs_xport_attach_cleanup;