| // SPDX-License-Identifier: GPL-2.0-or-later |
| /* |
| * IBM ASM Service Processor Device Driver |
| * |
| * Copyright (C) IBM Corporation, 2004 |
| * |
| * Author: Max Asböck <amax@us.ibm.com> |
| */ |
| |
| #include "ibmasm.h" |
| #include "dot_command.h" |
| |
| /** |
| * Dispatch an incoming message to the specific handler for the message. |
| * Called from interrupt context. |
| */ |
| void ibmasm_receive_message(struct service_processor *sp, void *message, int message_size) |
| { |
| u32 size; |
| struct dot_command_header *header = (struct dot_command_header *)message; |
| |
| if (message_size == 0) |
| return; |
| |
| size = get_dot_command_size(message); |
| if (size == 0) |
| return; |
| |
| if (size > message_size) |
| size = message_size; |
| |
| switch (header->type) { |
| case sp_event: |
| ibmasm_receive_event(sp, message, size); |
| break; |
| case sp_command_response: |
| ibmasm_receive_command_response(sp, message, size); |
| break; |
| case sp_heartbeat: |
| ibmasm_receive_heartbeat(sp, message, size); |
| break; |
| default: |
| dev_err(sp->dev, "Received unknown message from service processor\n"); |
| } |
| } |
| |
| |
| #define INIT_BUFFER_SIZE 32 |
| |
| |
| /** |
| * send the 4.3.5.10 dot command (driver VPD) to the service processor |
| */ |
| int ibmasm_send_driver_vpd(struct service_processor *sp) |
| { |
| struct command *command; |
| struct dot_command_header *header; |
| u8 *vpd_command; |
| u8 *vpd_data; |
| int result = 0; |
| |
| command = ibmasm_new_command(sp, INIT_BUFFER_SIZE); |
| if (command == NULL) |
| return -ENOMEM; |
| |
| header = (struct dot_command_header *)command->buffer; |
| header->type = sp_write; |
| header->command_size = 4; |
| header->data_size = 16; |
| header->status = 0; |
| header->reserved = 0; |
| |
| vpd_command = command->buffer + sizeof(struct dot_command_header); |
| vpd_command[0] = 0x4; |
| vpd_command[1] = 0x3; |
| vpd_command[2] = 0x5; |
| vpd_command[3] = 0xa; |
| |
| vpd_data = vpd_command + header->command_size; |
| vpd_data[0] = 0; |
| strcat(vpd_data, IBMASM_DRIVER_VPD); |
| vpd_data[10] = 0; |
| vpd_data[15] = 0; |
| |
| ibmasm_exec_command(sp, command); |
| ibmasm_wait_for_response(command, IBMASM_CMD_TIMEOUT_NORMAL); |
| |
| if (command->status != IBMASM_CMD_COMPLETE) |
| result = -ENODEV; |
| |
| command_put(command); |
| |
| return result; |
| } |
| |
| struct os_state_command { |
| struct dot_command_header header; |
| unsigned char command[3]; |
| unsigned char data; |
| }; |
| |
| /** |
| * send the 4.3.6 dot command (os state) to the service processor |
| * During driver init this function is called with os state "up". |
| * This causes the service processor to start sending heartbeats the |
| * driver. |
| * During driver exit the function is called with os state "down", |
| * causing the service processor to stop the heartbeats. |
| */ |
| int ibmasm_send_os_state(struct service_processor *sp, int os_state) |
| { |
| struct command *cmd; |
| struct os_state_command *os_state_cmd; |
| int result = 0; |
| |
| cmd = ibmasm_new_command(sp, sizeof(struct os_state_command)); |
| if (cmd == NULL) |
| return -ENOMEM; |
| |
| os_state_cmd = (struct os_state_command *)cmd->buffer; |
| os_state_cmd->header.type = sp_write; |
| os_state_cmd->header.command_size = 3; |
| os_state_cmd->header.data_size = 1; |
| os_state_cmd->header.status = 0; |
| os_state_cmd->command[0] = 4; |
| os_state_cmd->command[1] = 3; |
| os_state_cmd->command[2] = 6; |
| os_state_cmd->data = os_state; |
| |
| ibmasm_exec_command(sp, cmd); |
| ibmasm_wait_for_response(cmd, IBMASM_CMD_TIMEOUT_NORMAL); |
| |
| if (cmd->status != IBMASM_CMD_COMPLETE) |
| result = -ENODEV; |
| |
| command_put(cmd); |
| return result; |
| } |