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 /** !!! keep this in sync with scsi_periph module !!! */ 71 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 88 request->flags |= SCSI_DIR_OUT; 89 90 request->data = cmd->data; 91 request->sg_list = NULL; 92 request->data_len = cmd->data_length; 93 request->sort = -1; 94 request->timeout = cmd->timeout; 95 96 memcpy(request->cdb, cmd->command, SCSI_MAX_CDB_SIZE); 97 request->cdb_len = cmd->command_length; 98 99 device->scsi->sync_io(request); 100 101 // TBD: should we call standard error handler here, or may the 102 // actions done there (like starting the unit) confuse the application? 103 104 cmd->cam_status = request->subsys_status; 105 cmd->scsi_status = request->device_status; 106 107 if ((request->subsys_status & SCSI_AUTOSNS_VALID) != 0 && cmd->sense_data) { 108 memcpy(cmd->sense_data, request->sense, 109 min((int32)cmd->sense_data_length, SCSI_MAX_SENSE_SIZE - request->sense_resid)); 110 } 111 112 if ((cmd->flags & B_RAW_DEVICE_REPORT_RESIDUAL) != 0) { 113 // this is a bit strange, see Be's sample code where I pinched this from; 114 // normally, residual means "number of unused bytes left" 115 // but here, we have to return "number of used bytes", which is the opposite 116 cmd->data_length = cmd->data_length - request->data_resid; 117 cmd->sense_data_length = SCSI_MAX_SENSE_SIZE - request->sense_resid; 118 } 119 120 device->scsi->free_ccb(request); 121 return B_OK; 122 } 123 124 125 static status_t 126 raw_ioctl(raw_device_info *device, int op, void *buffer, size_t length) 127 { 128 status_t res; 129 130 switch (op) { 131 case B_RAW_DEVICE_COMMAND: 132 res = raw_command(device, buffer); 133 break; 134 135 default: 136 res = B_DEV_INVALID_IOCTL; 137 } 138 139 SHOW_FLOW(4, "%x: %s", op, strerror(res)); 140 141 return res; 142 } 143 144 145 static status_t 146 raw_init_device(device_node_handle node, void *user_cookie, void **cookie) 147 { 148 raw_device_info *device; 149 status_t res; 150 151 SHOW_FLOW0(3, ""); 152 153 device = (raw_device_info *)calloc(1, sizeof(*device)); 154 if (device == NULL) 155 return B_NO_MEMORY; 156 157 device->node = node; 158 159 // register it everywhere 160 res = pnp->init_driver(pnp->get_parent(node), NULL, 161 (driver_module_info **)&device->scsi, (void **)&device->scsi_device); 162 if (res != B_OK) 163 goto err; 164 165 SHOW_FLOW0(3, "done"); 166 167 *cookie = device; 168 return B_OK; 169 170 err: 171 free(device); 172 return res; 173 } 174 175 176 static status_t 177 raw_uninit_device(raw_device_info *device) 178 { 179 pnp->uninit_driver(pnp->get_parent(device->node)); 180 free(device); 181 182 return B_OK; 183 } 184 185 186 /** called whenever a new SCSI device was added to system; 187 * we register a devfs entry for every device 188 */ 189 190 static status_t 191 raw_device_added(device_node_handle node) 192 { 193 uint8 path_id, target_id, target_lun; 194 char name[100]; 195 196 SHOW_FLOW0(3, ""); 197 198 // compose name 199 if (pnp->get_attr_uint8(node, SCSI_BUS_PATH_ID_ITEM, &path_id, true) != B_OK 200 || pnp->get_attr_uint8(node, SCSI_DEVICE_TARGET_ID_ITEM, &target_id, true) != B_OK 201 || pnp->get_attr_uint8(node, SCSI_DEVICE_TARGET_LUN_ITEM, &target_lun, true) != B_OK) 202 return B_ERROR; 203 204 sprintf(name, "bus/scsi/%d/%d/%d/raw", 205 path_id, target_id, target_lun); 206 207 SHOW_FLOW(3, "name=%s", name); 208 209 // ready to register 210 { 211 device_attr attrs[] = { 212 { B_DRIVER_MODULE, B_STRING_TYPE, { string: SCSI_RAW_MODULE_NAME }}, 213 214 // default connection is used by peripheral drivers, and as we don't 215 // want to kick them out, we use concurrent "raw" connection 216 // (btw: this shows nicely that something goes wrong: one device 217 // and two drivers means begging for trouble) 218 { PNP_DRIVER_CONNECTION, B_STRING_TYPE, { string: "raw" }}, 219 220 // we want devfs on top of us (who wouldn't?) 221 { B_DRIVER_FIXED_CHILD, B_STRING_TYPE, { string: PNP_DEVFS_MODULE_NAME }}, 222 // tell which name we want to have in devfs 223 { PNP_DEVFS_FILENAME, B_STRING_TYPE, { string: name }}, 224 { NULL } 225 }; 226 227 return pnp->register_device(node, attrs, NULL, &node); 228 } 229 } 230 231 232 static status_t 233 std_ops(int32 op, ...) 234 { 235 switch (op) { 236 case B_MODULE_INIT: 237 case B_MODULE_UNINIT: 238 return B_OK; 239 240 default: 241 return B_ERROR; 242 } 243 } 244 245 246 module_dependency module_dependencies[] = { 247 { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&pnp }, 248 {} 249 }; 250 251 pnp_devfs_driver_info scsi_raw_module = { 252 { 253 { 254 SCSI_RAW_MODULE_NAME, 255 0, 256 std_ops 257 }, 258 259 NULL, 260 raw_device_added, 261 raw_init_device, 262 (status_t (*) (void *))raw_uninit_device, 263 NULL 264 }, 265 266 (status_t (*)(void *, uint32, void **)) &raw_open, 267 raw_close, 268 raw_free, 269 (status_t (*)(void *, uint32, void *, size_t)) &raw_ioctl, 270 271 raw_read, 272 raw_write, 273 274 NULL, 275 NULL, 276 277 NULL, 278 NULL 279 }; 280 281 module_info *modules[] = { 282 (module_info *)&scsi_raw_module, 283 NULL 284 }; 285