/** * hvcs_get_partner_info - Get all of the partner info for a vty-server adapter * @unit_address: The unit_address of the vty-server adapter for which this * function is fetching partner info. * @head: An initialized list_head pointer to an empty list to use to return the * list of partner info fetched from the hypervisor to the caller. * @pi_buff: A page sized buffer pre-allocated prior to calling this function * that is to be used to be used by firmware as an iterator to keep track * of the partner info retrieval. * * This function returns non-zero on success, or if there is no partner info. * * The pi_buff is pre-allocated prior to calling this function because this * function may be called with a spin_lock held and kmalloc of a page is not * recommended as GFP_ATOMIC. * * The first long of this buffer is used to store a partner unit address. The * second long is used to store a partner partition ID and starting at * pi_buff[2] is the 79 character Converged Location Code (diff size than the * unsigned longs, hence the casting mumbo jumbo you see later). * * Invocation of this function should always be followed by an invocation of * hvcs_free_partner_info() using a pointer to the SAME list head instance * that was passed as a parameter to this function. */ int hvcs_get_partner_info(uint32_t unit_address, struct list_head *head, unsigned long *pi_buff) { /* * Dealt with as longs because of the hcall interface even though the * values are uint32_t. */ unsigned long last_p_partition_ID; unsigned long last_p_unit_address; struct hvcs_partner_info *next_partner_info = NULL; int more = 1; int retval; memset(pi_buff, 0x00, PAGE_SIZE); /* invalid parameters */ if (!head || !pi_buff) return -EINVAL; last_p_partition_ID = last_p_unit_address = ~0UL; INIT_LIST_HEAD(head); do { retval = hvcs_next_partner(unit_address, last_p_partition_ID, last_p_unit_address, pi_buff); if (retval) { /* * Don't indicate that we've failed if we have * any list elements. */ if (!list_empty(head)) return 0; return retval; } last_p_partition_ID = be64_to_cpu(pi_buff[0]); last_p_unit_address = be64_to_cpu(pi_buff[1]); /* This indicates that there are no further partners */ if (last_p_partition_ID == ~0UL && last_p_unit_address == ~0UL) break; /* This is a very small struct and will be freed soon in * hvcs_free_partner_info(). */ next_partner_info = kmalloc(sizeof(struct hvcs_partner_info), GFP_ATOMIC); if (!next_partner_info) { printk(KERN_WARNING "HVCONSOLE: kmalloc() failed to" " allocate partner info struct.\n"); hvcs_free_partner_info(head); return -ENOMEM; } next_partner_info->unit_address = (unsigned int)last_p_unit_address; next_partner_info->partition_ID = (unsigned int)last_p_partition_ID; /* copy the Null-term char too */ strlcpy(&next_partner_info->location_code[0], (char *)&pi_buff[2], sizeof(next_partner_info->location_code)); list_add_tail(&(next_partner_info->node), head); next_partner_info = NULL; } while (more); return 0; }
int hvcs_get_partner_info(uint32_t unit_address, struct list_head *head, unsigned long *pi_buff) { unsigned long last_p_partition_ID; unsigned long last_p_unit_address; struct hvcs_partner_info *next_partner_info = NULL; int more = 1; int retval; memset(pi_buff, 0x00, PAGE_SIZE); if (!head || !pi_buff) return -EINVAL; last_p_partition_ID = last_p_unit_address = ~0UL; INIT_LIST_HEAD(head); do { retval = hvcs_next_partner(unit_address, last_p_partition_ID, last_p_unit_address, pi_buff); if (retval) { if (!list_empty(head)) return 0; return retval; } last_p_partition_ID = pi_buff[0]; last_p_unit_address = pi_buff[1]; if (last_p_partition_ID == ~0UL && last_p_unit_address == ~0UL) break; next_partner_info = kmalloc(sizeof(struct hvcs_partner_info), GFP_ATOMIC); if (!next_partner_info) { printk(KERN_WARNING "HVCONSOLE: kmalloc() failed to" " allocate partner info struct.\n"); hvcs_free_partner_info(head); return -ENOMEM; } next_partner_info->unit_address = (unsigned int)last_p_unit_address; next_partner_info->partition_ID = (unsigned int)last_p_partition_ID; strncpy(&next_partner_info->location_code[0], (char *)&pi_buff[2], strlen((char *)&pi_buff[2]) + 1); list_add_tail(&(next_partner_info->node), head); next_partner_info = NULL; } while (more); return 0; }