1 2/* 3 * IBM ASM Service Processor Device Driver 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 * 19 * Copyright (C) IBM Corporation, 2004 20 * 21 * Author: Max Asb��ck <amax@us.ibm.com> 22 * 23 */ 24 25#include <linux/sched.h> 26#include <linux/slab.h> 27#include "ibmasm.h" 28#include "lowlevel.h" 29 30static void exec_next_command(struct service_processor *sp); 31 32static atomic_t command_count = ATOMIC_INIT(0); 33 34struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_size) 35{ 36 struct command *cmd; 37 38 if (buffer_size > IBMASM_CMD_MAX_BUFFER_SIZE) 39 return NULL; 40 41 cmd = kzalloc(sizeof(struct command), GFP_KERNEL); 42 if (cmd == NULL) 43 return NULL; 44 45 46 cmd->buffer = kzalloc(buffer_size, GFP_KERNEL); 47 if (cmd->buffer == NULL) { 48 kfree(cmd); 49 return NULL; 50 } 51 cmd->buffer_size = buffer_size; 52 53 kref_init(&cmd->kref); 54 cmd->lock = &sp->lock; 55 56 cmd->status = IBMASM_CMD_PENDING; 57 init_waitqueue_head(&cmd->wait); 58 INIT_LIST_HEAD(&cmd->queue_node); 59 60 atomic_inc(&command_count); 61 dbg("command count: %d\n", atomic_read(&command_count)); 62 63 return cmd; 64} 65 66void ibmasm_free_command(struct kref *kref) 67{ 68 struct command *cmd = to_command(kref); 69 70 list_del(&cmd->queue_node); 71 atomic_dec(&command_count); 72 dbg("command count: %d\n", atomic_read(&command_count)); 73 kfree(cmd->buffer); 74 kfree(cmd); 75} 76 77static void enqueue_command(struct service_processor *sp, struct command *cmd) 78{ 79 list_add_tail(&cmd->queue_node, &sp->command_queue); 80} 81 82static struct command *dequeue_command(struct service_processor *sp) 83{ 84 struct command *cmd; 85 struct list_head *next; 86 87 if (list_empty(&sp->command_queue)) 88 return NULL; 89 90 next = sp->command_queue.next; 91 list_del_init(next); 92 cmd = list_entry(next, struct command, queue_node); 93 94 return cmd; 95} 96 97static inline void do_exec_command(struct service_processor *sp) 98{ 99 char tsbuf[32]; 100 101 dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf)); 102 103 if (ibmasm_send_i2o_message(sp)) { 104 sp->current_command->status = IBMASM_CMD_FAILED; 105 wake_up(&sp->current_command->wait); 106 command_put(sp->current_command); 107 exec_next_command(sp); 108 } 109} 110 111/** 112 * exec_command 113 * send a command to a service processor 114 * Commands are executed sequentially. One command (sp->current_command) 115 * is sent to the service processor. Once the interrupt handler gets a 116 * message of type command_response, the message is copied into 117 * the current commands buffer, 118 */ 119void ibmasm_exec_command(struct service_processor *sp, struct command *cmd) 120{ 121 unsigned long flags; 122 char tsbuf[32]; 123 124 dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf)); 125 126 spin_lock_irqsave(&sp->lock, flags); 127 128 if (!sp->current_command) { 129 sp->current_command = cmd; 130 command_get(sp->current_command); 131 spin_unlock_irqrestore(&sp->lock, flags); 132 do_exec_command(sp); 133 } else { 134 enqueue_command(sp, cmd); 135 spin_unlock_irqrestore(&sp->lock, flags); 136 } 137} 138 139static void exec_next_command(struct service_processor *sp) 140{ 141 unsigned long flags; 142 char tsbuf[32]; 143 144 dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf)); 145 146 spin_lock_irqsave(&sp->lock, flags); 147 sp->current_command = dequeue_command(sp); 148 if (sp->current_command) { 149 command_get(sp->current_command); 150 spin_unlock_irqrestore(&sp->lock, flags); 151 do_exec_command(sp); 152 } else { 153 spin_unlock_irqrestore(&sp->lock, flags); 154 } 155} 156 157/** 158 * Sleep until a command has failed or a response has been received 159 * and the command status been updated by the interrupt handler. 160 * (see receive_response). 161 */ 162void ibmasm_wait_for_response(struct command *cmd, int timeout) 163{ 164 wait_event_interruptible_timeout(cmd->wait, 165 cmd->status == IBMASM_CMD_COMPLETE || 166 cmd->status == IBMASM_CMD_FAILED, 167 timeout * HZ); 168} 169 170/** 171 * receive_command_response 172 * called by the interrupt handler when a dot command of type command_response 173 * was received. 174 */ 175void ibmasm_receive_command_response(struct service_processor *sp, void *response, size_t size) 176{ 177 struct command *cmd = sp->current_command; 178 179 if (!sp->current_command) 180 return; 181 182 memcpy_fromio(cmd->buffer, response, min(size, cmd->buffer_size)); 183 cmd->status = IBMASM_CMD_COMPLETE; 184 wake_up(&sp->current_command->wait); 185 command_put(sp->current_command); 186 exec_next_command(sp); 187} 188