diff options
-rw-r--r-- | usr/src/uts/common/io/fibre-channel/ulp/fcp.c | 89 | ||||
-rw-r--r-- | usr/src/uts/common/sys/fibre-channel/impl/fctl.h | 3 |
2 files changed, 87 insertions, 5 deletions
diff --git a/usr/src/uts/common/io/fibre-channel/ulp/fcp.c b/usr/src/uts/common/io/fibre-channel/ulp/fcp.c index e3c3ad63f0..f6a3bd0ec6 100644 --- a/usr/src/uts/common/io/fibre-channel/ulp/fcp.c +++ b/usr/src/uts/common/io/fibre-channel/ulp/fcp.c @@ -427,6 +427,7 @@ static void fcp_handle_devices(struct fcp_port *pptr, static int fcp_handle_mapflags(struct fcp_port *pptr, struct fcp_tgt *ptgt, fc_portmap_t *map_entry, int link_cnt, int tgt_cnt, int cause); +static int fcp_handle_reportlun_changed(struct fcp_tgt *ptgt, int cause); static int fcp_send_els(struct fcp_port *pptr, struct fcp_tgt *ptgt, struct fcp_ipkt *icmd, uchar_t opcode, int lcount, int tcount, int cause); static void fcp_update_state(struct fcp_port *pptr, uint32_t state, @@ -716,7 +717,7 @@ extern dev_info_t *scsi_vhci_dip; (es)->es_add_code == 0x25 && \ (es)->es_qual_code == 0x0) -#define FCP_VERSION "1.188" +#define FCP_VERSION "1.189" #define FCP_NAME_VERSION "SunFC FCP v" FCP_VERSION #define FCP_NUM_ELEMENTS(array) \ @@ -4700,6 +4701,7 @@ fcp_handle_devices(struct fcp_port *pptr, fc_portmap_t devlist[], if (map_entry->map_type == PORT_DEVICE_OLD || map_entry->map_type == PORT_DEVICE_NEW || + map_entry->map_type == PORT_DEVICE_REPORTLUN_CHANGED || map_entry->map_type == PORT_DEVICE_CHANGED) { FCP_TRACE(fcp_logq, pptr->port_instbuf, fcp_trace, FCP_BUF_LEVEL_2, 0, @@ -4713,6 +4715,7 @@ fcp_handle_devices(struct fcp_port *pptr, fc_portmap_t devlist[], case PORT_DEVICE_USER_CREATE: case PORT_DEVICE_USER_LOGIN: case PORT_DEVICE_NEW: + case PORT_DEVICE_REPORTLUN_CHANGED: FCP_TGT_TRACE(ptgt, map_tag[i], FCP_TGT_TRACE_1); if (fcp_handle_mapflags(pptr, ptgt, map_entry, @@ -4811,6 +4814,61 @@ fcp_handle_devices(struct fcp_port *pptr, fc_portmap_t devlist[], } } +static int +fcp_handle_reportlun_changed(struct fcp_tgt *ptgt, int cause) +{ + struct fcp_lun *plun; + struct fcp_port *pptr; + int rscn_count; + int lun0_newalloc; + int ret = TRUE; + + ASSERT(ptgt); + pptr = ptgt->tgt_port; + lun0_newalloc = 0; + if ((plun = fcp_get_lun(ptgt, 0)) == NULL) { + /* + * no LUN struct for LUN 0 yet exists, + * so create one + */ + plun = fcp_alloc_lun(ptgt); + if (plun == NULL) { + fcp_log(CE_WARN, pptr->port_dip, + "!Failed to allocate lun 0 for" + " D_ID=%x", ptgt->tgt_d_id); + return (ret); + } + lun0_newalloc = 1; + } + + mutex_enter(&ptgt->tgt_mutex); + /* + * consider lun 0 as device not connected if it is + * offlined or newly allocated + */ + if ((plun->lun_state & FCP_LUN_OFFLINE) || lun0_newalloc) { + plun->lun_state |= FCP_LUN_DEVICE_NOT_CONNECTED; + } + plun->lun_state |= (FCP_LUN_BUSY | FCP_LUN_MARK); + plun->lun_state &= ~FCP_LUN_OFFLINE; + ptgt->tgt_lun_cnt = 1; + ptgt->tgt_report_lun_cnt = 0; + mutex_exit(&ptgt->tgt_mutex); + + rscn_count = fc_ulp_get_rscn_count(pptr->port_fp_handle); + if (fcp_send_scsi(plun, SCMD_REPORT_LUN, + sizeof (struct fcp_reportlun_resp), pptr->port_link_cnt, + ptgt->tgt_change_cnt, cause, rscn_count) != DDI_SUCCESS) { + FCP_TRACE(fcp_logq, pptr->port_instbuf, + fcp_trace, FCP_BUF_LEVEL_3, 0, "!Failed to send REPORTLUN " + "to D_ID=%x", ptgt->tgt_d_id); + } else { + ret = FALSE; + } + + return (ret); +} + /* * Function: fcp_handle_mapflags * @@ -4908,6 +4966,21 @@ fcp_handle_mapflags(struct fcp_port *pptr, struct fcp_tgt *ptgt, } /* + * if UA'REPORT_LUN_CHANGED received, + * send out REPORT LUN promptly, skip PLOGI/PRLI process + */ + if (map_entry->map_type == PORT_DEVICE_REPORTLUN_CHANGED) { + ptgt->tgt_state &= ~(FCP_TGT_OFFLINE | FCP_TGT_MARK); + mutex_exit(&ptgt->tgt_mutex); + mutex_exit(&pptr->port_mutex); + + ret = fcp_handle_reportlun_changed(ptgt, cause); + + mutex_enter(&pptr->port_mutex); + return (ret); + } + + /* * If ptgt was NULL when this function was entered, then tgt_node_state * was never specifically initialized but zeroed out which means * FCP_TGT_NODE_NONE. @@ -10762,8 +10835,9 @@ fcp_virt_tgt_init(dev_info_t *hba_dip, dev_info_t *tgt_dip, if ((scsi_device_prop_lookup_byte_array(sd, SCSI_DEVICE_PROP_PATH, PORT_WWN_PROP, &bytes, &nbytes) != DDI_PROP_SUCCESS) || (nbytes != FC_WWN_SIZE)) { - if (bytes) + if (bytes) { scsi_device_prop_free(sd, SCSI_DEVICE_PROP_PATH, bytes); + } return (DDI_NOT_WELL_FORMED); } @@ -11245,6 +11319,14 @@ fcp_pkt_setup(struct scsi_pkt *pkt, fpkt = cmd->cmd_fp_pkt; fpkt->pkt_data_acc = NULL; + /* + * When port_state is FCP_STATE_OFFLINE, remote_port (tgt_pd_handle) + * could be destroyed. We need fail pkt_setup. + */ + if (pptr->port_state & FCP_STATE_OFFLINE) { + return (-1); + } + mutex_enter(&ptgt->tgt_mutex); fpkt->pkt_pd = ptgt->tgt_pd_handle; @@ -14513,7 +14595,6 @@ fcp_call_finish_init_held(struct fcp_port *pptr, struct fcp_tgt *ptgt, return (rval); } - static void fcp_reconfigure_luns(void * tgt_handle) { @@ -14548,7 +14629,7 @@ fcp_reconfigure_luns(void * tgt_handle) bcopy(&ptgt->tgt_port_wwn.raw_wwn[0], &devlist->map_pwwn, FC_WWN_SIZE); devlist->map_state = PORT_DEVICE_LOGGED_IN; - devlist->map_type = PORT_DEVICE_NEW; + devlist->map_type = PORT_DEVICE_REPORTLUN_CHANGED; devlist->map_flags = 0; fcp_statec_callback(NULL, pptr->port_fp_handle, FC_STATE_DEVICE_CHANGE, diff --git a/usr/src/uts/common/sys/fibre-channel/impl/fctl.h b/usr/src/uts/common/sys/fibre-channel/impl/fctl.h index 7985c97b70..db66561121 100644 --- a/usr/src/uts/common/sys/fibre-channel/impl/fctl.h +++ b/usr/src/uts/common/sys/fibre-channel/impl/fctl.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -321,6 +321,7 @@ typedef struct fc_trace_logq { #define PORT_DEVICE_USER_LOGOUT 0x6 /* only for changelist->map_type */ #define PORT_DEVICE_USER_CREATE 0x7 /* only for changelist->map_type */ #define PORT_DEVICE_USER_DELETE 0x8 /* only for changelist->map_type */ +#define PORT_DEVICE_REPORTLUN_CHANGED 0x9 /* only for changelist->map_type */ /* * Flags used for fc_portmap->map_type |