/*-
* Copyright (c) 2004,2009 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
int n, nevents;
isns_kevent_handler *evt_handler_p;
int run_thread;
run_thread = 1;
while (run_thread) {
/* if no task outstanding, check queue here and send PDU */
while ((cfg_p->curtask_p == NULL)
&& ((cfg_p->curtask_p = isns_get_next_task(cfg_p)) != NULL))
isns_run_task(cfg_p->curtask_p);
more = (bavail > 0);
while (more) {
if (cfg_p->pdu_in_p == NULL) {
/*
* Try to form a valid pdu by starting with the hdr.
* If there isn't enough data in the socket buffer
* to form a full hdr, just return.
*
* Once we have read in our hdr, allocate all buffers
* needed.
*/
if (bavail < (int64_t)sizeof(struct isns_pdu_hdr_s))
return 0;
/* Form a placeholder pdu */
pdu_p = isns_new_pdu(cfg_p, 0, 0, 0);
/* Read the header into our placeholder pdu */
read_buf[0].iov_base = &(pdu_p->hdr);
read_buf[0].iov_len = sizeof(struct isns_pdu_hdr_s);
iovcnt = 1;
bavail -= sizeof(struct isns_pdu_hdr_s);
/*
* ToDo: read until sizeof(struct isns_pdu_hdr_s) has
* been read in. This statement should be
*
* bavail -= rv;
*/
/* Try to sense early whether we might have garbage */
if (pdu_p->hdr.isnsp_version != ISNSP_VERSION) {
DBG("isns_kevent_socket: pdu_p->hdr."
"isnsp_version != ISNSP_VERSION\n");
isns_free_pdu(pdu_p);
/* Hold on to our placeholder pdu */
cfg_p->pdu_in_p = pdu_p;
more = (bavail > 0) ? 1 : 0;
} else if (bavail > 0) {
/*
* Fill in the pdu payload data.
*
* If we can fill it all in now
* -AND- it corresponds to the active transaction
* then add the pdu to the transaction's
* pdu_rsp_list
* -AND- it does not correspond to the active
* transaction (or there is no active
* transaction) then drop it on the floor.
* We may not be able to fill it all in now.
* -EITHER WAY- fill in as much payload data now
* as we can.
*/
/* Refer to our placeholder pdu */
pdu_p = cfg_p->pdu_in_p;
/* How much payload data has been filled in? */
cur_len = 0;
curbuf_p = pdu_p->payload_p;
while (curbuf_p->cur_len == curbuf_p->alloc_len) {
cur_len += curbuf_p->cur_len;
curbuf_p = curbuf_p->next;
}
cur_len += curbuf_p->cur_len;
/* How much payload data is left to be filled in? */
unread_len = pdu_p->hdr.payload_len - cur_len;
/* Read as much remaining payload data as possible */
iovcnt = 0;
while (curbuf_p->next != NULL) {
read_buf[iovcnt].iov_base = isns_buffer_data(
curbuf_p, curbuf_p->cur_len);
read_buf[iovcnt].iov_len = curbuf_p->alloc_len -
curbuf_p->cur_len;
iovcnt++;
/* Update cur_len in buffers that newly have data */
curbuf_p = pdu_p->payload_p;
while (curbuf_p->cur_len == curbuf_p->alloc_len)
curbuf_p = curbuf_p->next;
/* If refresh info pointer NULL, or no name assigned, just return. */
ref_p = cfg_p->refresh_p;
if ((ref_p == NULL) || (ref_p->node[0] == '\0'))
return 0;
if (ref_p->trans_p != NULL) {
/* If the previous refresh trans is not complete, return. */
rval = isns_get_pdu_response_status(ref_p->trans_p, &status);
if (rval == EPERM) {
DBG("isns_kevent_timer_refresh: "
"prev refresh trans not complete\n");
return 0;
}
/* Free previous refresh trans. */
isns_free_trans(ref_p->trans_p);
ref_p->trans_p = NULL;
}
/* Build new refresh transaction and send it. */
trans = isns_new_trans((ISNS_HANDLE)cfg_p, isnsp_DevAttrQry, 0);
if (trans == ISNS_INVALID_TRANS) {
DBG("isns_kevent_timer_refresh: error on isns_new_trans()\n");
return 0;
}
ref_p->trans_p = (struct isns_trans_s *)trans;
/* First we add our source attribute */
isns_add_string(trans, isnst_iSCSIName, ref_p->node);
/* Now add our message attribute */
isns_add_string(trans, isnst_iSCSIName, ref_p->node);
isns_add_tlv(trans, isnst_Delimiter, 0, NULL);
/* and finally the operating attributes */
isns_add_tlv(trans, isnst_EID, 0, NULL);
isns_send_trans(trans, NULL, NULL);