/* * bnx2i_iscsi.c: QLogic NetXtreme II iSCSI driver. * * Copyright (c) 2006 - 2013 Broadcom Corporation * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. * Copyright (c) 2007, 2008 Mike Christie * Copyright (c) 2014, QLogic Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation. * * Written by: Anil Veerabhadrappa (anilgv@broadcom.com) * Previously Maintained by: Eddie Wai (eddie.wai@broadcom.com) * Maintained by: QLogic-Storage-Upstream@qlogic.com
*/
/** * bnx2i_get_write_cmd_bd_idx - identifies various BD bookmarks * @cmd: iscsi cmd struct pointer * @buf_off: absolute buffer offset * @start_bd_off: u32 pointer to return the offset within the BD * indicated by 'start_bd_idx' on which 'buf_off' falls * @start_bd_idx: index of the BD on which 'buf_off' falls * * identifies & marks various bd info for scsi command's imm data, * unsolicited data and the first solicited data seq.
*/ staticvoid bnx2i_get_write_cmd_bd_idx(struct bnx2i_cmd *cmd, u32 buf_off,
u32 *start_bd_off, u32 *start_bd_idx)
{ struct iscsi_bd *bd_tbl = cmd->io_tbl.bd_tbl;
u32 cur_offset = 0;
u32 cur_bd_idx = 0;
if (buf_off) { while (buf_off >= (cur_offset + bd_tbl->buffer_length)) {
cur_offset += bd_tbl->buffer_length;
cur_bd_idx++;
bd_tbl++;
}
}
/** * bnx2i_setup_write_cmd_bd_info - sets up BD various information * @task: transport layer's cmd struct pointer * * identifies & marks various bd info for scsi command's immediate data, * unsolicited data and first solicited data seq which includes BD start * index & BD buf off. his function takes into account iscsi parameter such * as immediate data and unsolicited data is support on this connection.
*/ staticvoid bnx2i_setup_write_cmd_bd_info(struct iscsi_task *task)
{ struct bnx2i_cmd *cmd = task->dd_data;
u32 start_bd_offset;
u32 start_bd_idx;
u32 buffer_offset = 0;
u32 cmd_len = cmd->req.total_data_transfer_length;
/* if ImmediateData is turned off & IntialR2T is turned on, * there will be no immediate or unsolicited data, just return.
*/ if (!iscsi_task_has_unsol_data(task) && !task->imm_count) return;
/* Immediate data */
buffer_offset += task->imm_count; if (task->imm_count == cmd_len) return;
/** * bnx2i_alloc_iscsi_cid - allocates a iscsi_cid from free pool * @hba: pointer to adapter instance
*/ static u32 bnx2i_alloc_iscsi_cid(struct bnx2i_hba *hba)
{ int idx;
/** * bnx2i_free_iscsi_cid - returns tcp port to free list * @hba: pointer to adapter instance * @iscsi_cid: iscsi context ID to free
*/ staticvoid bnx2i_free_iscsi_cid(struct bnx2i_hba *hba, u16 iscsi_cid)
{ int idx;
/** * bnx2i_alloc_ep - allocates ep structure from global pool * @hba: pointer to adapter instance * * routine allocates a free endpoint structure from global pool and * a tcp port to be used for this connection. Global resource lock, * 'bnx2i_resc_lock' is held while accessing shared global data structures
*/ staticstruct iscsi_endpoint *bnx2i_alloc_ep(struct bnx2i_hba *hba)
{ struct iscsi_endpoint *ep; struct bnx2i_endpoint *bnx2i_ep;
u32 ec_div;
ep = iscsi_create_endpoint(sizeof(*bnx2i_ep)); if (!ep) {
printk(KERN_ERR "bnx2i: Could not allocate ep\n"); return NULL;
}
/** * bnx2i_free_mp_bdt - releases ITT back to free pool * @hba: pointer to adapter instance * * free MP dummy buffer and associated BD table
*/ staticvoid bnx2i_free_mp_bdt(struct bnx2i_hba *hba)
{ if (hba->mp_bd_tbl) {
dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
hba->mp_bd_tbl, hba->mp_bd_dma);
hba->mp_bd_tbl = NULL;
} if (hba->dummy_buffer) {
dma_free_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
hba->dummy_buffer, hba->dummy_buf_dma);
hba->dummy_buffer = NULL;
} return;
}
/** * bnx2i_drop_session - notifies iscsid of connection error. * @cls_session: iscsi cls session pointer * * This notifies iscsid that there is a error, so it can initiate * recovery. * * This relies on caller using the iscsi class iterator so the object * is refcounted and does not disapper from under us.
*/ void bnx2i_drop_session(struct iscsi_cls_session *cls_session)
{
iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED);
}
/** * bnx2i_ep_destroy_list_add - add an entry to EP destroy list * @hba: pointer to adapter instance * @ep: pointer to endpoint (transport identifier) structure * * EP destroy queue manager
*/ staticint bnx2i_ep_destroy_list_add(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
{
write_lock_bh(&hba->ep_rdwr_lock);
list_add_tail(&ep->link, &hba->ep_destroy_list);
write_unlock_bh(&hba->ep_rdwr_lock); return 0;
}
/** * bnx2i_ep_destroy_list_del - add an entry to EP destroy list * * @hba: pointer to adapter instance * @ep: pointer to endpoint (transport identifier) structure * * EP destroy queue manager
*/ staticint bnx2i_ep_destroy_list_del(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
{
write_lock_bh(&hba->ep_rdwr_lock);
list_del_init(&ep->link);
write_unlock_bh(&hba->ep_rdwr_lock);
return 0;
}
/** * bnx2i_ep_ofld_list_add - add an entry to ep offload pending list * @hba: pointer to adapter instance * @ep: pointer to endpoint (transport identifier) structure * * pending conn offload completion queue manager
*/ staticint bnx2i_ep_ofld_list_add(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
{
write_lock_bh(&hba->ep_rdwr_lock);
list_add_tail(&ep->link, &hba->ep_ofld_list);
write_unlock_bh(&hba->ep_rdwr_lock); return 0;
}
/** * bnx2i_ep_ofld_list_del - add an entry to ep offload pending list * @hba: pointer to adapter instance * @ep: pointer to endpoint (transport identifier) structure * * pending conn offload completion queue manager
*/ staticint bnx2i_ep_ofld_list_del(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
{
write_lock_bh(&hba->ep_rdwr_lock);
list_del_init(&ep->link);
write_unlock_bh(&hba->ep_rdwr_lock); return 0;
}
/** * bnx2i_find_ep_in_ofld_list - find iscsi_cid in pending list of endpoints * * @hba: pointer to adapter instance * @iscsi_cid: iscsi context ID to find *
*/ struct bnx2i_endpoint *
bnx2i_find_ep_in_ofld_list(struct bnx2i_hba *hba, u32 iscsi_cid)
{ struct list_head *list; struct list_head *tmp; struct bnx2i_endpoint *ep = NULL;
read_lock_bh(&hba->ep_rdwr_lock);
list_for_each_safe(list, tmp, &hba->ep_ofld_list) {
ep = (struct bnx2i_endpoint *)list;
if (ep->ep_iscsi_cid == iscsi_cid) break;
ep = NULL;
}
read_unlock_bh(&hba->ep_rdwr_lock);
if (!ep)
printk(KERN_ERR "l5 cid %d not found\n", iscsi_cid); return ep;
}
/** * bnx2i_find_ep_in_destroy_list - find iscsi_cid in destroy list * @hba: pointer to adapter instance * @iscsi_cid: iscsi context ID to find *
*/ struct bnx2i_endpoint *
bnx2i_find_ep_in_destroy_list(struct bnx2i_hba *hba, u32 iscsi_cid)
{ struct list_head *list; struct list_head *tmp; struct bnx2i_endpoint *ep = NULL;
read_lock_bh(&hba->ep_rdwr_lock);
list_for_each_safe(list, tmp, &hba->ep_destroy_list) {
ep = (struct bnx2i_endpoint *)list;
if (ep->ep_iscsi_cid == iscsi_cid) break;
ep = NULL;
}
read_unlock_bh(&hba->ep_rdwr_lock);
if (!ep)
printk(KERN_ERR "l5 cid %d not found\n", iscsi_cid);
return ep;
}
/** * bnx2i_ep_active_list_add - add an entry to ep active list * @hba: pointer to adapter instance * @ep: pointer to endpoint (transport identifier) structure * * current active conn queue manager
*/ staticvoid bnx2i_ep_active_list_add(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
{
write_lock_bh(&hba->ep_rdwr_lock);
list_add_tail(&ep->link, &hba->ep_active_list);
write_unlock_bh(&hba->ep_rdwr_lock);
}
/** * bnx2i_ep_active_list_del - deletes an entry to ep active list * @hba: pointer to adapter instance * @ep: pointer to endpoint (transport identifier) structure * * current active conn queue manager
*/ staticvoid bnx2i_ep_active_list_del(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
{
write_lock_bh(&hba->ep_rdwr_lock);
list_del_init(&ep->link);
write_unlock_bh(&hba->ep_rdwr_lock);
}
/** * bnx2i_setup_host_queue_size - assigns shost->can_queue param * @hba: pointer to adapter instance * @shost: scsi host pointer * * Initializes 'can_queue' parameter based on how many outstanding commands * the device can handle. Each device 5708/5709/57710 has different * capabilities
*/ staticvoid bnx2i_setup_host_queue_size(struct bnx2i_hba *hba, struct Scsi_Host *shost)
{ if (test_bit(BNX2I_NX2_DEV_5708, &hba->cnic_dev_type))
shost->can_queue = ISCSI_MAX_CMDS_PER_HBA_5708; elseif (test_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type))
shost->can_queue = ISCSI_MAX_CMDS_PER_HBA_5709; elseif (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type))
shost->can_queue = ISCSI_MAX_CMDS_PER_HBA_57710; else
shost->can_queue = ISCSI_MAX_CMDS_PER_HBA_5708;
}
/** * bnx2i_alloc_hba - allocate and init adapter instance * @cnic: cnic device pointer * * allocate & initialize adapter structure and call other * support routines to do per adapter initialization
*/ struct bnx2i_hba *bnx2i_alloc_hba(struct cnic_dev *cnic)
{ struct Scsi_Host *shost; struct bnx2i_hba *hba;
/* * mgmt task or cmd was never sent to us to transmit.
*/ if (!task->sc || task->state == ISCSI_TASK_PENDING) return; /* * need to clean-up task context to claim dma buffers
*/ if (task->state == ISCSI_TASK_ABRT_TMF) {
bnx2i_send_cmd_cleanup_req(hba, task->dd_data);
/** * bnx2i_session_create - create a new iscsi session * @ep: pointer to iscsi endpoint * @cmds_max: user specified maximum commands * @qdepth: scsi queue depth to support * @initial_cmdsn: initial iscsi CMDSN to be used for this session * * Creates a new iSCSI session instance on given device.
*/ staticstruct iscsi_cls_session *
bnx2i_session_create(struct iscsi_endpoint *ep,
uint16_t cmds_max, uint16_t qdepth,
uint32_t initial_cmdsn)
{ struct Scsi_Host *shost; struct iscsi_cls_session *cls_session; struct bnx2i_hba *hba; struct bnx2i_endpoint *bnx2i_ep;
if (!ep) {
printk(KERN_ERR "bnx2i: missing ep.\n"); return NULL;
}
/* * user can override hw limit as long as it is within * the min/max.
*/ if (cmds_max > hba->max_sqes)
cmds_max = hba->max_sqes; elseif (cmds_max < BNX2I_SQ_WQES_MIN)
cmds_max = BNX2I_SQ_WQES_MIN;
/** * bnx2i_conn_bind - binds iscsi sess, conn and ep objects together * @cls_session: pointer to iscsi cls session * @cls_conn: pointer to iscsi cls conn * @transport_fd: 64-bit EP handle * @is_leading: leading connection on this session? * * Binds together iSCSI session instance, iSCSI connection instance * and the TCP connection. This routine returns error code if * TCP connection does not belong on the device iSCSI sess/conn * is bound
*/ staticint bnx2i_conn_bind(struct iscsi_cls_session *cls_session, struct iscsi_cls_conn *cls_conn,
uint64_t transport_fd, int is_leading)
{ struct iscsi_conn *conn = cls_conn->dd_data; struct bnx2i_conn *bnx2i_conn = conn->dd_data; struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); struct bnx2i_hba *hba = iscsi_host_priv(shost); struct bnx2i_endpoint *bnx2i_ep; struct iscsi_endpoint *ep; int ret_code;
ep = iscsi_lookup_endpoint(transport_fd); if (!ep) return -EINVAL; /* * Forcefully terminate all in progress connection recovery at the * earliest, either in bind(), send_pdu(LOGIN), or conn_start()
*/ if (bnx2i_adapter_ready(hba)) {
ret_code = -EIO; goto put_ep;
}
bnx2i_ep = ep->dd_data; if ((bnx2i_ep->state == EP_STATE_TCP_FIN_RCVD) ||
(bnx2i_ep->state == EP_STATE_TCP_RST_RCVD)) { /* Peer disconnect via' FIN or RST */
ret_code = -EINVAL; goto put_ep;
}
/* 5706/5708/5709 FW takes RQ as full when initiated, but for 57710 * driver needs to explicitly replenish RQ index during setup.
*/ if (test_bit(BNX2I_NX2_DEV_57710, &bnx2i_ep->hba->cnic_dev_type))
bnx2i_put_rq_buf(bnx2i_conn, 0);
/* * this should normally not sleep for a long time so it should * not disrupt the caller.
*/
timer_setup(&bnx2i_conn->ep->ofld_timer, bnx2i_ep_ofld_timer, 0);
bnx2i_conn->ep->ofld_timer.expires = 1 * HZ + jiffies;
add_timer(&bnx2i_conn->ep->ofld_timer); /* update iSCSI context for this conn, wait for CNIC to complete */
wait_event_interruptible(bnx2i_conn->ep->ofld_wait,
bnx2i_conn->ep->state != EP_STATE_ULP_UPDATE_START);
if (signal_pending(current))
flush_signals(current);
timer_delete_sync(&bnx2i_conn->ep->ofld_timer);
/** * bnx2i_check_route - checks if target IP route belongs to one of NX2 devices * @dst_addr: target IP address * * check if route resolves to BNX2 device
*/ staticstruct bnx2i_hba *bnx2i_check_route(struct sockaddr *dst_addr)
{ struct sockaddr_in *desti = (struct sockaddr_in *) dst_addr; struct bnx2i_hba *hba; struct cnic_dev *cnic = NULL;
hba = get_adapter_list_head(); if (hba && hba->cnic)
cnic = hba->cnic->cm_select_dev(desti, CNIC_ULP_ISCSI); if (!cnic) {
printk(KERN_ALERT "bnx2i: no route," "can't connect using cnic\n"); goto no_nx2_route;
}
hba = bnx2i_find_hba_for_cnic(cnic); if (!hba) goto no_nx2_route;
if (bnx2i_adapter_ready(hba)) {
printk(KERN_ALERT "bnx2i: check route, hba not found\n"); goto no_nx2_route;
} if (hba->netdev->mtu > hba->mtu_supported) {
printk(KERN_ALERT "bnx2i: %s network i/f mtu is set to %d\n",
hba->netdev->name, hba->netdev->mtu);
printk(KERN_ALERT "bnx2i: iSCSI HBA can support mtu of %d\n",
hba->mtu_supported); goto no_nx2_route;
} return hba;
no_nx2_route: return NULL;
}
/** * bnx2i_tear_down_conn - tear down iscsi/tcp connection and free resources * @hba: pointer to adapter instance * @ep: endpoint (transport identifier) structure * * destroys cm_sock structure and on chip iscsi context
*/ staticint bnx2i_tear_down_conn(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep)
{ if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic) && ep->cm_sk)
hba->cnic->cm_destroy(ep->cm_sk);
if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type) &&
ep->state == EP_STATE_DISCONN_TIMEDOUT) { if (ep->conn && ep->conn->cls_conn &&
ep->conn->cls_conn->dd_data) { struct iscsi_conn *conn = ep->conn->cls_conn->dd_data;
/* Must suspend all rx queue activity for this ep */
set_bit(ISCSI_CONN_FLAG_SUSPEND_RX, &conn->flags);
} /* CONN_DISCONNECT timeout may or may not be an issue depending * on what transcribed in TCP layer, different targets behave * differently
*/
printk(KERN_ALERT "bnx2i (%s): - WARN - CONN_DISCON timed out, " "please submit GRC Dump, NW/PCIe trace, " "driver msgs to developers for analysis\n",
hba->netdev->name);
}
if (signal_pending(current))
flush_signals(current);
timer_delete_sync(&ep->ofld_timer);
bnx2i_ep_destroy_list_del(hba, ep);
if (ep->state != EP_STATE_CLEANUP_CMPL) /* should never happen */
printk(KERN_ALERT "bnx2i - conn destroy failed\n");
return 0;
}
/** * bnx2i_ep_connect - establish TCP connection to target portal * @shost: scsi host * @dst_addr: target IP address * @non_blocking: blocking or non-blocking call * * this routine initiates the TCP/IP connection by invoking Option-2 i/f * with l5_core and the CNIC. This is a multi-step process of resolving * route to target, create a iscsi connection context, handshaking with * CNIC module to create/initialize the socket struct and finally * sending down option-2 request to complete TCP 3-way handshake
*/ staticstruct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, int non_blocking)
{
u32 iscsi_cid = BNX2I_CID_RESERVED; struct sockaddr_in *desti = (struct sockaddr_in *) dst_addr; struct sockaddr_in6 *desti6; struct bnx2i_endpoint *bnx2i_ep; struct bnx2i_hba *hba; struct cnic_dev *cnic; struct cnic_sockaddr saddr; struct iscsi_endpoint *ep; int rc = 0;
if (shost) { /* driver is given scsi host to work with */
hba = iscsi_host_priv(shost);
} else /* * check if the given destination can be reached through * a iscsi capable NetXtreme2 device
*/
hba = bnx2i_check_route(dst_addr);
if (!hba) {
rc = -EINVAL; goto nohba;
}
mutex_lock(&hba->net_dev_lock);
if (bnx2i_adapter_ready(hba) || !hba->cid_que.cid_free_cnt) {
rc = -EPERM; goto check_busy;
}
cnic = hba->cnic;
ep = bnx2i_alloc_ep(hba); if (!ep) {
rc = -ENOMEM; goto check_busy;
}
bnx2i_ep = ep->dd_data;
/** * bnx2i_ep_tcp_conn_active - check EP state transition * @bnx2i_ep: endpoint pointer * * check if underlying TCP connection is active
*/ staticint bnx2i_ep_tcp_conn_active(struct bnx2i_endpoint *bnx2i_ep)
{ int ret; int cnic_dev_10g = 0;
if (test_bit(BNX2I_NX2_DEV_57710, &bnx2i_ep->hba->cnic_dev_type))
cnic_dev_10g = 1;
switch (bnx2i_ep->state) { case EP_STATE_CLEANUP_FAILED: case EP_STATE_OFLD_FAILED: case EP_STATE_DISCONN_TIMEDOUT:
ret = 0; break; case EP_STATE_CONNECT_START: case EP_STATE_CONNECT_FAILED: case EP_STATE_CONNECT_COMPL: case EP_STATE_ULP_UPDATE_START: case EP_STATE_ULP_UPDATE_COMPL: case EP_STATE_TCP_FIN_RCVD: case EP_STATE_LOGOUT_SENT: case EP_STATE_LOGOUT_RESP_RCVD: case EP_STATE_ULP_UPDATE_FAILED:
ret = 1; break; case EP_STATE_TCP_RST_RCVD: if (cnic_dev_10g)
ret = 0; else
ret = 1; break; default:
ret = 0;
}
return ret;
}
/** * bnx2i_hw_ep_disconnect - executes TCP connection teardown process in the hw * @bnx2i_ep: TCP connection (bnx2i endpoint) handle * * executes TCP connection teardown process
*/ int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep)
{ struct bnx2i_hba *hba = bnx2i_ep->hba; struct cnic_dev *cnic; struct iscsi_session *session = NULL; struct iscsi_conn *conn = NULL; int ret = 0; int close = 0; int close_ret = 0;
if (!hba) return 0;
cnic = hba->cnic; if (!cnic) return 0;
if (bnx2i_ep->state == EP_STATE_IDLE ||
bnx2i_ep->state == EP_STATE_DISCONN_TIMEDOUT) return 0;
if (!bnx2i_ep_tcp_conn_active(bnx2i_ep)) goto destroy_conn;
if (bnx2i_ep->conn) {
conn = bnx2i_ep->conn->cls_conn->dd_data;
session = conn->session;
}
/* driver should not attempt connection cleanup until TCP_CONNECT * completes either successfully or fails. Timeout is 9-secs, so * wait for it to complete
*/ while ((bnx2i_ep->state == EP_STATE_CONNECT_START) &&
!time_after(jiffies, bnx2i_ep->timestamp + (12 * HZ)))
msleep(250);
if (bnx2i_ep->conn)
bnx2i_conn = bnx2i_ep->conn;
hba = bnx2i_ep->hba;
mutex_lock(&hba->net_dev_lock);
if (bnx2i_ep->state == EP_STATE_DISCONN_TIMEDOUT) goto out;
if (bnx2i_ep->state == EP_STATE_IDLE) goto free_resc;
/* Do all chip cleanup here */ if (bnx2i_hw_ep_disconnect(bnx2i_ep)) {
mutex_unlock(&hba->net_dev_lock); return;
}
free_resc:
bnx2i_free_qp_resc(hba, bnx2i_ep);
/* handled by cnic driver */
hba->cnic->iscsi_nl_msg_recv(hba->cnic, ISCSI_UEVENT_PATH_UPDATE, buf,
len);
return 0;
}
static umode_t bnx2i_attr_is_visible(int param_type, int param)
{ switch (param_type) { case ISCSI_HOST_PARAM: switch (param) { case ISCSI_HOST_PARAM_NETDEV_NAME: case ISCSI_HOST_PARAM_HWADDRESS: case ISCSI_HOST_PARAM_IPADDRESS: return S_IRUGO; default: return 0;
} case ISCSI_PARAM: switch (param) { case ISCSI_PARAM_MAX_RECV_DLENGTH: case ISCSI_PARAM_MAX_XMIT_DLENGTH: case ISCSI_PARAM_HDRDGST_EN: case ISCSI_PARAM_DATADGST_EN: case ISCSI_PARAM_CONN_ADDRESS: case ISCSI_PARAM_CONN_PORT: case ISCSI_PARAM_EXP_STATSN: case ISCSI_PARAM_PERSISTENT_ADDRESS: case ISCSI_PARAM_PERSISTENT_PORT: case ISCSI_PARAM_PING_TMO: case ISCSI_PARAM_RECV_TMO: case ISCSI_PARAM_INITIAL_R2T_EN: case ISCSI_PARAM_MAX_R2T: case ISCSI_PARAM_IMM_DATA_EN: case ISCSI_PARAM_FIRST_BURST: case ISCSI_PARAM_MAX_BURST: case ISCSI_PARAM_PDU_INORDER_EN: case ISCSI_PARAM_DATASEQ_INORDER_EN: case ISCSI_PARAM_ERL: case ISCSI_PARAM_TARGET_NAME: case ISCSI_PARAM_TPGT: case ISCSI_PARAM_USERNAME: case ISCSI_PARAM_PASSWORD: case ISCSI_PARAM_USERNAME_IN: case ISCSI_PARAM_PASSWORD_IN: case ISCSI_PARAM_FAST_ABORT: case ISCSI_PARAM_ABORT_TMO: case ISCSI_PARAM_LU_RESET_TMO: case ISCSI_PARAM_TGT_RESET_TMO: case ISCSI_PARAM_IFACE_NAME: case ISCSI_PARAM_INITIATOR_NAME: case ISCSI_PARAM_BOOT_ROOT: case ISCSI_PARAM_BOOT_NIC: case ISCSI_PARAM_BOOT_TARGET: return S_IRUGO; default: return 0;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.