1 /* 2 * Copyright 2002/03, Thomas Kurschel. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 /* 7 Part of Open SCSI raw driver. 8 9 We don't support particular file handles, instead we use 10 file handle = device handle. 11 */ 12 13 14 #include "scsi_raw.h" 15 #include <string.h> 16 #include <scsi.h> 17 #include <malloc.h> 18 #include <pnp_devfs.h> 19 #include <stdio.h> 20 21 22 device_manager_info *pnp; 23 24 25 static status_t 26 raw_open(void *device_cookie, uint32 flags, void **handle_cookie) 27 { 28 *handle_cookie = device_cookie; 29 return B_OK; 30 } 31 32 33 static status_t 34 raw_close(void *cookie) 35 { 36 return B_OK; 37 } 38 39 40 static status_t 41 raw_free(void *cookie) 42 { 43 return B_OK; 44 } 45 46 47 #if 0 48 static status_t 49 raw_control(void *cookie, uint32 op, void *data, size_t len) 50 { 51 return B_OK; 52 } 53 #endif 54 55 56 static status_t 57 raw_read(void *cookie, off_t position, void *data, size_t *numBytes) 58 { 59 return B_ERROR; 60 } 61 62 63 static status_t 64 raw_write(void *cookie, off_t position, const void *data, size_t *numBytes) 65 { 66 return B_ERROR; 67 } 68 69 70 /* TODO: sync with scsi_periph module, this has been updated there to use 71 user_memcpy */ 72 static status_t 73 raw_command(raw_device_info *device, raw_device_command *cmd) 74 { 75 scsi_ccb *request; 76 77 SHOW_FLOW0(3, ""); 78 79 request = device->scsi->alloc_ccb(device->scsi_device); 80 if (request == NULL) 81 return B_NO_MEMORY; 82 83 request->flags = 0; 84 85 if (cmd->flags & B_RAW_DEVICE_DATA_IN) 86 request->flags |= SCSI_DIR_IN; 87 else if (cmd->data_length) 88 request->flags |= SCSI_DIR_OUT; 89 else 90 request->flags |= SCSI_DIR_NONE; 91 92 request->data = cmd->data; 93 request->sg_list = NULL; 94 request->data_len = cmd->data_length; 95 request->sort = -1; 96 request->timeout = cmd->timeout; 97 98 memcpy(request->cdb, cmd->command, SCSI_MAX_CDB_SIZE); 99 request->cdb_len = cmd->command_length; 100 101 device->scsi->sync_io(request); 102 103 // TBD: should we call standard error handler here, or may the 104 // actions done there (like starting the unit) confuse the application? 105 106 cmd->cam_status = request->subsys_status; 107 cmd->scsi_status = request->device_status; 108 109 if ((request->subsys_status & SCSI_AUTOSNS_VALID) != 0 && cmd->sense_data) { 110 memcpy(cmd->sense_data, request->sense, 111 min((int32)cmd->sense_data_length, SCSI_MAX_SENSE_SIZE - request->sense_resid)); 112 } 113 114 if ((cmd->flags & B_RAW_DEVICE_REPORT_RESIDUAL) != 0) { 115 // this is a bit strange, see Be's sample code where I pinched this from; 116 // normally, residual means "number of unused bytes left" 117 // but here, we have to return "number of used bytes", which is the opposite 118 cmd->data_length = cmd->data_length - request->data_resid; 119 cmd->sense_data_length = SCSI_MAX_SENSE_SIZE - request->sense_resid; 120 } 121 122 device->scsi->free_ccb(request); 123 return B_OK; 124 } 125 126 127 static status_t 128 raw_ioctl(raw_device_info *device, int op, void *buffer, size_t length) 129 { 130 status_t res; 131 132 switch (op) { 133 case B_RAW_DEVICE_COMMAND: 134 res = raw_command(device, buffer); 135 break; 136 137 default: 138 res = B_DEV_INVALID_IOCTL; 139 } 140 141 SHOW_FLOW(4, "%x: %s", op, strerror(res)); 142 143 return res; 144 } 145 146 147 static status_t 148 raw_init_device(device_node_handle node, void *user_cookie, void **cookie) 149 { 150 raw_device_info *device; 151 status_t res; 152 153 SHOW_FLOW0(3, ""); 154 155 device = (raw_device_info *)calloc(1, sizeof(*device)); 156 if (device == NULL) 157 return B_NO_MEMORY; 158 159 device->node = node; 160 161 // register it everywhere 162 res = pnp->init_driver(pnp->get_parent(node), NULL, 163 (driver_module_info **)&device->scsi, (void **)&device->scsi_device); 164 if (res != B_OK) 165 goto err; 166 167 SHOW_FLOW0(3, "done"); 168 169 *cookie = device; 170 return B_OK; 171 172 err: 173 free(device); 174 return res; 175 } 176 177 178 static status_t 179 raw_uninit_device(raw_device_info *device) 180 { 181 pnp->uninit_driver(pnp->get_parent(device->node)); 182 free(device); 183 184 return B_OK; 185 } 186 187 188 /** called whenever a new SCSI device was added to system; 189 * we register a devfs entry for every device 190 */ 191 192 static status_t 193 raw_device_added(device_node_handle node) 194 { 195 uint8 path_id, target_id, target_lun; 196 char name[100]; 197 198 SHOW_FLOW0(3, ""); 199 200 // compose name 201 if (pnp->get_attr_uint8(node, SCSI_BUS_PATH_ID_ITEM, &path_id, true) != B_OK 202 || pnp->get_attr_uint8(node, SCSI_DEVICE_TARGET_ID_ITEM, &target_id, true) != B_OK 203 || pnp->get_attr_uint8(node, SCSI_DEVICE_TARGET_LUN_ITEM, &target_lun, true) != B_OK) 204 return B_ERROR; 205 206 sprintf(name, "bus/scsi/%d/%d/%d/raw", 207 path_id, target_id, target_lun); 208 209 SHOW_FLOW(3, "name=%s", name); 210 211 // ready to register 212 { 213 device_attr attrs[] = { 214 { B_DRIVER_MODULE, B_STRING_TYPE, { .string = SCSI_RAW_MODULE_NAME }}, 215 216 // default connection is used by peripheral drivers, and as we don't 217 // want to kick them out, we use concurrent "raw" connection 218 // (btw: this shows nicely that something goes wrong: one device 219 // and two drivers means begging for trouble) 220 { PNP_DRIVER_CONNECTION, B_STRING_TYPE, { .string = "raw" }}, 221 222 // we want devfs on top of us (who wouldn't?) 223 { B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { .string = PNP_DEVFS_MODULE_NAME }}, 224 // tell which name we want to have in devfs 225 { PNP_DEVFS_FILENAME, B_STRING_TYPE, { .string = name }}, 226 { NULL } 227 }; 228 229 return pnp->register_device(node, attrs, NULL, &node); 230 } 231 } 232 233 234 static status_t 235 std_ops(int32 op, ...) 236 { 237 switch (op) { 238 case B_MODULE_INIT: 239 case B_MODULE_UNINIT: 240 return B_OK; 241 242 default: 243 return B_ERROR; 244 } 245 } 246 247 248 module_dependency module_dependencies[] = { 249 { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp }, 250 {} 251 }; 252 253 pnp_devfs_driver_info scsi_raw_module = { 254 { 255 { 256 SCSI_RAW_MODULE_NAME, 257 0, 258 std_ops 259 }, 260 261 NULL, 262 raw_device_added, 263 raw_init_device, 264 (status_t (*) (void *))raw_uninit_device, 265 NULL 266 }, 267 268 (status_t (*)(void *, uint32, void **)) &raw_open, 269 raw_close, 270 raw_free, 271 (status_t (*)(void *, uint32, void *, size_t)) &raw_ioctl, 272 273 raw_read, 274 raw_write, 275 276 NULL, 277 NULL, 278 279 NULL, 280 NULL 281 }; 282 283 module_info *modules[] = { 284 (module_info *)&scsi_raw_module, 285 NULL 286 }; 287